Bitcoin Core  31.0.0
P2P Digital Currency
bitcoin.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-present 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 #include <bitcoin-build-config.h> // IWYU pragma: keep
6 
7 #include <qt/bitcoin.h>
8 
9 #include <chainparams.h>
10 #include <common/args.h>
11 #include <common/init.h>
12 #include <common/system.h>
13 #include <init.h>
14 #include <interfaces/handler.h>
15 #include <interfaces/init.h>
16 #include <interfaces/node.h>
17 #include <logging.h>
18 #include <node/context.h>
19 #include <node/interface_ui.h>
20 #include <noui.h>
21 #include <qt/bitcoingui.h>
22 #include <qt/clientmodel.h>
23 #include <qt/guiconstants.h>
24 #include <qt/guiutil.h>
25 #include <qt/initexecutor.h>
26 #include <qt/intro.h>
27 #include <qt/networkstyle.h>
28 #include <qt/optionsmodel.h>
29 #include <qt/platformstyle.h>
30 #include <qt/splashscreen.h>
31 #include <qt/utilitydialog.h>
32 #include <qt/winshutdownmonitor.h>
33 #include <uint256.h>
34 #include <util/exception.h>
35 #include <util/string.h>
36 #include <util/threadnames.h>
37 #include <util/translation.h>
38 #include <validation.h>
39 
40 #ifdef ENABLE_WALLET
41 #include <qt/paymentserver.h>
42 #include <qt/walletcontroller.h>
43 #include <qt/walletmodel.h>
44 #include <wallet/types.h>
45 #endif // ENABLE_WALLET
46 
47 #include <boost/signals2/connection.hpp>
48 #include <chrono>
49 #include <memory>
50 
51 #include <QApplication>
52 #include <QDebug>
53 #include <QLatin1String>
54 #include <QLibraryInfo>
55 #include <QLocale>
56 #include <QMessageBox>
57 #include <QSettings>
58 #include <QThread>
59 #include <QTimer>
60 #include <QTranslator>
61 #include <QWindow>
62 
63 // Declare meta types used for QMetaObject::invokeMethod
64 Q_DECLARE_METATYPE(bool*)
65 Q_DECLARE_METATYPE(CAmount)
66 Q_DECLARE_METATYPE(SynchronizationState)
67 Q_DECLARE_METATYPE(SyncType)
68 Q_DECLARE_METATYPE(uint256)
69 #ifdef ENABLE_WALLET
70 Q_DECLARE_METATYPE(wallet::AddressPurpose)
71 #endif // ENABLE_WALLET
72 
74 
75 static void RegisterMetaTypes()
76 {
77  // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
78  qRegisterMetaType<bool*>();
79  qRegisterMetaType<SynchronizationState>();
80  qRegisterMetaType<SyncType>();
81  #ifdef ENABLE_WALLET
82  qRegisterMetaType<WalletModel*>();
83  qRegisterMetaType<wallet::AddressPurpose>();
84  #endif // ENABLE_WALLET
85  // Register typedefs (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType)
86  // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
87  qRegisterMetaType<CAmount>("CAmount");
88  qRegisterMetaType<size_t>("size_t");
89 
90  qRegisterMetaType<std::function<void()>>("std::function<void()>");
91  qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
92  qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
93  qRegisterMetaType<BitcoinUnit>("BitcoinUnit");
94 }
95 
96 static QString GetLangTerritory()
97 {
98  QSettings settings;
99  // Get desired locale (e.g. "de_DE")
100  // 1) System default language
101  QString lang_territory = QLocale::system().name();
102  // 2) Language from QSettings
103  QString lang_territory_qsettings = settings.value("language", "").toString();
104  if(!lang_territory_qsettings.isEmpty())
105  lang_territory = lang_territory_qsettings;
106  // 3) -lang command line argument
107  lang_territory = QString::fromStdString(gArgs.GetArg("-lang", lang_territory.toStdString()));
108  return lang_territory;
109 }
110 
112 static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
113 {
114  // Remove old translators
115  QApplication::removeTranslator(&qtTranslatorBase);
116  QApplication::removeTranslator(&qtTranslator);
117  QApplication::removeTranslator(&translatorBase);
118  QApplication::removeTranslator(&translator);
119 
120  // Get desired locale (e.g. "de_DE")
121  // 1) System default language
122  QString lang_territory = GetLangTerritory();
123 
124  // Convert to "de" only by truncating "_DE"
125  QString lang = lang_territory;
126  lang.truncate(lang_territory.lastIndexOf('_'));
127 
128  // Load language files for configured locale:
129  // - First load the translator for the base language, without territory
130  // - Then load the more specific locale translator
131 
132  const QString translation_path{QLibraryInfo::path(QLibraryInfo::TranslationsPath)};
133  // Load e.g. qt_de.qm
134  if (qtTranslatorBase.load("qt_" + lang, translation_path)) {
135  QApplication::installTranslator(&qtTranslatorBase);
136  }
137 
138  // Load e.g. qt_de_DE.qm
139  if (qtTranslator.load("qt_" + lang_territory, translation_path)) {
140  QApplication::installTranslator(&qtTranslator);
141  }
142 
143  // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
144  if (translatorBase.load(lang, ":/translations/")) {
145  QApplication::installTranslator(&translatorBase);
146  }
147 
148  // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
149  if (translator.load(lang_territory, ":/translations/")) {
150  QApplication::installTranslator(&translator);
151  }
152 }
153 
154 static bool ErrorSettingsRead(const bilingual_str& error, const std::vector<std::string>& details)
155 {
156  QMessageBox messagebox(QMessageBox::Critical, CLIENT_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Reset | QMessageBox::Abort);
157  /*: Explanatory text shown on startup when the settings file cannot be read.
158  Prompts user to make a choice between resetting or aborting. */
159  messagebox.setInformativeText(QObject::tr("Do you want to reset settings to default values, or to abort without making changes?"));
160  messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
161  messagebox.setTextFormat(Qt::PlainText);
162  messagebox.setDefaultButton(QMessageBox::Reset);
163  switch (messagebox.exec()) {
164  case QMessageBox::Reset:
165  return false;
166  case QMessageBox::Abort:
167  return true;
168  default:
169  assert(false);
170  }
171 }
172 
173 static void ErrorSettingsWrite(const bilingual_str& error, const std::vector<std::string>& details)
174 {
175  QMessageBox messagebox(QMessageBox::Critical, CLIENT_NAME, QString::fromStdString(strprintf("%s.", error.translated)), QMessageBox::Ok);
176  /*: Explanatory text shown on startup when the settings file could not be written.
177  Prompts user to check that we have the ability to write to the file.
178  Explains that the user has the option of running without a settings file.*/
179  messagebox.setInformativeText(QObject::tr("A fatal error occurred. Check that settings file is writable, or try running with -nosettings."));
180  messagebox.setDetailedText(QString::fromStdString(MakeUnorderedList(details)));
181  messagebox.setTextFormat(Qt::PlainText);
182  messagebox.setDefaultButton(QMessageBox::Ok);
183  messagebox.exec();
184 }
185 
186 /* qDebug() message handler --> debug.log */
187 void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
188 {
189  Q_UNUSED(context);
190  if (type == QtDebugMsg) {
191  LogDebug(BCLog::QT, "GUI: %s\n", msg.toStdString());
192  } else {
193  LogInfo("GUI: %s", msg.toStdString());
194  }
195 }
196 
197 static int qt_argc = 1;
198 static const char* qt_argv = "bitcoin-qt";
199 
201  : QApplication(qt_argc, const_cast<char**>(&qt_argv))
202 {
203  // Qt runs setlocale(LC_ALL, "") on initialization.
205  setQuitOnLastWindowClosed(false);
206 }
207 
209 {
210  // UI per-platform customization
211  // This must be done inside the BitcoinApplication constructor, or after it, because
212  // PlatformStyle::instantiate requires a QApplication
213  std::string platformName;
214  platformName = gArgs.GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
215  platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
216  if (!platformStyle) // Fall back to "other" if specified name not found
219 }
220 
222 {
223  m_executor.reset();
224 
225  delete window;
226  window = nullptr;
227  delete platformStyle;
228  platformStyle = nullptr;
229 }
230 
231 #ifdef ENABLE_WALLET
232 void BitcoinApplication::createPaymentServer()
233 {
234  paymentServer = new PaymentServer(this);
235 }
236 #endif
237 
239 {
240  optionsModel = new OptionsModel(node(), this);
241  if (resetSettings) {
242  optionsModel->Reset();
243  }
244  bilingual_str error;
245  if (!optionsModel->Init(error)) {
246  fs::path settings_path;
247  if (gArgs.GetSettingsPath(&settings_path)) {
248  error += Untranslated("\n");
249  std::string quoted_path = strprintf("%s", fs::quoted(fs::PathToString(settings_path)));
250  error.original += strprintf("Settings file %s might be corrupt or invalid.", quoted_path);
251  error.translated += tr("Settings file %1 might be corrupt or invalid.").arg(QString::fromStdString(quoted_path)).toStdString();
252  }
253  InitError(error);
254  QMessageBox::critical(nullptr, CLIENT_NAME, QString::fromStdString(error.translated));
255  return false;
256  }
257  return true;
258 }
259 
261 {
262  window = new BitcoinGUI(node(), platformStyle, networkStyle, nullptr);
264 
265  pollShutdownTimer = new QTimer(window);
266  connect(pollShutdownTimer, &QTimer::timeout, [this]{
267  if (!QApplication::activeModalWidget()) {
269  }
270  });
271 }
272 
274 {
275  assert(!m_splash);
276  m_splash = new SplashScreen(networkStyle);
277  m_splash->show();
278 }
279 
281 {
282  assert(!m_node);
283  m_node = init.makeNode();
285 }
286 
288 {
289  return node().baseInitialize();
290 }
291 
293 {
294  assert(!m_executor);
295  m_executor.emplace(node());
296 
297  /* communication to and from thread */
299  connect(&m_executor.value(), &InitExecutor::shutdownResult, this, [] {
300  QCoreApplication::exit(0);
301  });
305 }
306 
308 {
309  // Default printtoconsole to false for the GUI. GUI programs should not
310  // print to the console unnecessarily.
311  gArgs.SoftSetBoolArg("-printtoconsole", false);
312 
315 }
316 
318 {
320 }
321 
323 {
324  qDebug() << __func__ << ": Requesting initialize";
325  startThread();
326  Q_EMIT requestedInitialize();
327 }
328 
330 {
331  for (const auto w : QGuiApplication::topLevelWindows()) {
332  w->hide();
333  }
334 
335  delete m_splash;
336  m_splash = nullptr;
337 
338  // Show a simple window indicating shutdown status
339  // Do this first as some of the steps may take some time below,
340  // for example the RPC console may still be executing a command.
342 
343  qDebug() << __func__ << ": Requesting shutdown";
344 
345  // Must disconnect node signals otherwise current thread can deadlock since
346  // no event loop is running.
348  // Request node shutdown, which can interrupt long operations, like
349  // rescanning a wallet.
350  node().startShutdown();
351  // Prior to unsetting the client model, stop listening backend signals
352  if (clientModel) {
353  clientModel->stop();
354  }
355 
356  // Unsetting the client model can cause the current thread to wait for node
357  // to complete an operation, like wait for a RPC execution to complete.
358  window->setClientModel(nullptr);
359  pollShutdownTimer->stop();
360 
361 #ifdef ENABLE_WALLET
362  // Delete wallet controller here manually, instead of relying on Qt object
363  // tracking (https://doc.qt.io/qt-5/objecttrees.html). This makes sure
364  // walletmodel m_handle_* notification handlers are deleted before wallets
365  // are unloaded, which can simplify wallet implementations. It also avoids
366  // these notifications having to be handled while GUI objects are being
367  // destroyed, making GUI code less fragile as well.
368  delete m_wallet_controller;
369  m_wallet_controller = nullptr;
370 #endif // ENABLE_WALLET
371 
372  delete clientModel;
373  clientModel = nullptr;
374 
375  // Request shutdown from core thread
376  Q_EMIT requestedShutdown();
377 }
378 
380 {
381  qDebug() << __func__ << ": Initialization result: " << success;
382 
383  if (!success || m_node->shutdownRequested()) {
384  requestShutdown();
385  return;
386  }
387 
388  delete m_splash;
389  m_splash = nullptr;
390 
391  // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
392  qInfo() << "Platform customization:" << platformStyle->getName();
394  window->setClientModel(clientModel, &tip_info);
395 
396  // If '-min' option passed, start window minimized (iconified) or minimized to tray
397  bool start_minimized = gArgs.GetBoolArg("-min", false);
398 #ifdef ENABLE_WALLET
400  m_wallet_controller = new WalletController(*clientModel, platformStyle, this);
401  window->setWalletController(m_wallet_controller, /*show_loading_minimized=*/start_minimized);
402  if (paymentServer) {
403  paymentServer->setOptionsModel(optionsModel);
404  }
405  }
406 #endif // ENABLE_WALLET
407 
408  // Show or minimize window
409  if (!start_minimized) {
410  window->show();
412  // do nothing as the window is managed by the tray icon
413  } else {
414  window->showMinimized();
415  }
416  Q_EMIT windowShown(window);
417 
418 #ifdef ENABLE_WALLET
419  // Now that initialization/startup is done, process any command-line
420  // bitcoin: URIs or payment requests:
421  if (paymentServer) {
422  connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
424  connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
425  window->message(title, message, style);
426  });
427  QTimer::singleShot(100ms, paymentServer, &PaymentServer::uiReady);
428  }
429 #endif
431 }
432 
433 void BitcoinApplication::handleRunawayException(const QString &message)
434 {
435  QMessageBox::critical(
436  nullptr, tr("Runaway exception"),
437  tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(CLIENT_NAME) +
438  QLatin1String("<br><br>") + GUIUtil::MakeHtmlLink(message, CLIENT_BUGREPORT));
439  ::exit(EXIT_FAILURE);
440 }
441 
443 {
444  assert(QThread::currentThread() == thread());
445  QMessageBox::warning(
446  nullptr, tr("Internal error"),
447  tr("An internal error occurred. %1 will attempt to continue safely. This is "
448  "an unexpected bug which can be reported as described below.").arg(CLIENT_NAME) +
449  QLatin1String("<br><br>") + GUIUtil::MakeHtmlLink(message, CLIENT_BUGREPORT));
450 }
451 
453 {
454  if (!window)
455  return 0;
456 
457  return window->winId();
458 }
459 
461 {
462  if (e->type() == QEvent::Quit) {
463  requestShutdown();
464  return true;
465  }
466 
467  return QApplication::event(e);
468 }
469 
470 static void SetupUIArgs(ArgsManager& argsman)
471 {
472  argsman.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
473  argsman.AddArg("-lang=<lang>", "Set language, for example \"de_DE\" (default: system locale)", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
474  argsman.AddArg("-min", "Start minimized", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
475  argsman.AddArg("-resetguisettings", "Reset all settings changed in the GUI", ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
476  argsman.AddArg("-splash", strprintf("Show splash screen on startup (default: %u)", DEFAULT_SPLASHSCREEN), ArgsManager::ALLOW_ANY, OptionsCategory::GUI);
477  argsman.AddArg("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::GUI);
478 }
479 
480 int GuiMain(int argc, char* argv[])
481 {
482  std::unique_ptr<interfaces::Init> init = interfaces::MakeGuiInit(argc, argv);
483 
486 
487  // Subscribe to global signals from core
488  boost::signals2::scoped_connection handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox);
489  boost::signals2::scoped_connection handler_question = ::uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion);
490  boost::signals2::scoped_connection handler_init_message = ::uiInterface.InitMessage_connect(noui_InitMessage);
491 
492  // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
493 
495  Q_INIT_RESOURCE(bitcoin);
496  Q_INIT_RESOURCE(bitcoin_locale);
497 
498 #if defined(QT_QPA_PLATFORM_ANDROID)
499  QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
500  QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
501  QApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
502 #endif
503 
504  BitcoinApplication app;
505  GUIUtil::LoadFont(QStringLiteral(":/fonts/monospace"));
506 
508  // Command-line options take precedence:
509  SetupServerArgs(gArgs, init->canListenIpc());
511  std::string error;
512  if (!gArgs.ParseParameters(argc, argv, error)) {
513  InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
514  // Create a message box, because the gui has neither been created nor has subscribed to core signals
515  QMessageBox::critical(nullptr, CLIENT_NAME,
516  // message cannot be translated because translations have not been initialized
517  QString::fromStdString("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
518  return EXIT_FAILURE;
519  }
520 
521  // Error out when loose non-argument tokens are encountered on command line
522  // However, allow BIP-21 URIs only if no options follow
523  bool payment_server_token_seen = false;
524  for (int i = 1; i < argc; i++) {
525  QString arg(argv[i]);
526  bool invalid_token = !arg.startsWith("-");
527 #ifdef ENABLE_WALLET
528  if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) {
529  invalid_token &= false;
530  payment_server_token_seen = true;
531  }
532 #endif
533  if (payment_server_token_seen && arg.startsWith("-")) {
534  InitError(Untranslated(strprintf("Options ('%s') cannot follow a BIP-21 payment URI", argv[i])));
535  QMessageBox::critical(nullptr, CLIENT_NAME,
536  // message cannot be translated because translations have not been initialized
537  QString::fromStdString("Options ('%1') cannot follow a BIP-21 payment URI").arg(QString::fromStdString(argv[i])));
538  return EXIT_FAILURE;
539  }
540  if (invalid_token) {
541  InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoin-qt -h for a list of options.", argv[i])));
542  QMessageBox::critical(nullptr, CLIENT_NAME,
543  // message cannot be translated because translations have not been initialized
544  QString::fromStdString("Command line contains unexpected token '%1', see bitcoin-qt -h for a list of options.").arg(QString::fromStdString(argv[i])));
545  return EXIT_FAILURE;
546  }
547  }
548 
549  // Now that the QApplication is setup and we have parsed our parameters, we can set the platform style
550  app.setupPlatformStyle();
551 
553  // must be set before OptionsModel is initialized or translations are loaded,
554  // as it is used to locate QSettings
555  QApplication::setOrganizationName(QAPP_ORG_NAME);
556  QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
557  QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
558 
560  // Now that QSettings are accessible, initialize translations
561  QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
562  initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
563 
564  // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
565  // but before showing splash screen.
566  if (HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
567  HelpMessageDialog help(nullptr, gArgs.GetBoolArg("-version", false));
568  help.showOrPrint();
569  return EXIT_SUCCESS;
570  }
571 
572  // Install global event filter that makes sure that long tooltips can be word-wrapped
573  app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
574 
576  // User language is set up: pick a data directory
577  bool did_show_intro = false;
578  int64_t prune_MiB = 0; // Intro dialog prune configuration
579  // Gracefully exit if the user cancels
580  if (!Intro::showIfNeeded(did_show_intro, prune_MiB)) return EXIT_SUCCESS;
581 
584  // - Do not call gArgs.GetDataDirNet() before this step finishes
585  // - Do not call Params() before this step
586  // - QSettings() will use the new application name after this, resulting in network-specific settings
587  // - Needs to be done before createOptionsModel
588  if (auto error = common::InitConfig(gArgs, ErrorSettingsRead)) {
589  InitError(error->message, error->details);
590  if (error->status == common::ConfigStatus::FAILED_WRITE) {
591  // Show a custom error message to provide more information in the
592  // case of a datadir write error.
593  ErrorSettingsWrite(error->message, error->details);
594  } else if (error->status != common::ConfigStatus::ABORTED) {
595  // Show a generic message in other cases, and no additional error
596  // message in the case of a read error if the user decided to abort.
597  QMessageBox::critical(nullptr, CLIENT_NAME, QObject::tr("Error: %1").arg(QString::fromStdString(error->message.translated)));
598  }
599  return EXIT_FAILURE;
600  }
601 #ifdef ENABLE_WALLET
602  // Parse URIs on command line
604 #endif
605 
606  QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().GetChainType()));
607  assert(!networkStyle.isNull());
608  // Allow for separate UI settings for testnets
609  QApplication::setApplicationName(networkStyle->getAppName());
610  // Re-initialize translations after changing application name (language in network-specific settings can be different)
611  initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
612 
613 #ifdef ENABLE_WALLET
614  // - Do this early as we don't want to bother initializing if we are just calling IPC
616  // - Do this *after* setting up the data directory, as the data directory hash is used in the name
617  // of the server.
618  // - Do this after creating app and setting up translations, so errors are
619  // translated properly.
621  exit(EXIT_SUCCESS);
622 
623  // Start up the payment server early, too, so impatient users that click on
624  // bitcoin: links repeatedly have their payment requests routed to this process:
626  app.createPaymentServer();
627  }
628 #endif // ENABLE_WALLET
629 
631  // Install global event filter that makes sure that out-of-focus labels do not contain text cursor.
632  app.installEventFilter(new GUIUtil::LabelOutOfFocusEventFilter(&app));
633 #if defined(Q_OS_WIN)
634  // Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
635  // Note: it is safe to call app.node() in the lambda below despite the fact
636  // that app.createNode() hasn't been called yet, because native events will
637  // not be processed until the Qt event loop is executed.
638  qApp->installNativeEventFilter(new WinShutdownMonitor([&app] { app.node().startShutdown(); }));
639 #endif
640  // Install qDebug() message handler to route to debug.log
641  qInstallMessageHandler(DebugMessageHandler);
642  // Allow parameter interaction before we create the options model
643  app.parameterSetup();
645 
646  if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false))
647  app.createSplashScreen(networkStyle.data());
648 
649  app.createNode(*init);
650 
651  // Load GUI settings from QSettings
652  if (!app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false))) {
653  return EXIT_FAILURE;
654  }
655 
656  if (did_show_intro) {
657  // Store intro dialog settings other than datadir (network specific)
658  app.InitPruneSetting(prune_MiB);
659  }
660 
661  try
662  {
663  app.createWindow(networkStyle.data());
664  // Perform base initialization before spinning up initialization/shutdown thread
665  // This is acceptable because this function only contains steps that are quick to execute,
666  // so the GUI thread won't be held up.
667  if (app.baseInitialize()) {
668  app.requestInitialize();
669 #if defined(Q_OS_WIN)
670  WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely…").arg(CLIENT_NAME), (HWND)app.getMainWinId());
671 #endif
672  app.exec();
673  } else {
674  // A dialog with detailed error will have been shown by InitError()
675  return EXIT_FAILURE;
676  }
677  } catch (const std::exception& e) {
678  PrintExceptionContinue(&e, "Runaway exception");
679  app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
680  } catch (...) {
681  PrintExceptionContinue(nullptr, "Runaway exception");
682  app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
683  }
684  return app.node().getExitStatus();
685 }
OptionsModel * optionsModel
Definition: bitcoin.h:94
void unsubscribeFromCoreSignals()
Disconnect core signals from GUI client.
static const bool DEFAULT_CHOOSE_DATADIR
Definition: intro.h:14
static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
Set up translations.
Definition: bitcoin.cpp:112
static void ErrorSettingsWrite(const bilingual_str &error, const std::vector< std::string > &details)
Definition: bitcoin.cpp:173
void DebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
Definition: bitcoin.cpp:187
void quitRequested()
void setupPlatformStyle()
Setup platform style.
Definition: bitcoin.cpp:208
return EXIT_SUCCESS
void receivedURI(const QString &uri)
Signal raised when a URI was entered or dragged to the GUI.
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition: init.cpp:853
void LogQtInfo()
Writes to debug.log short info about the used Qt and the host system.
Definition: guiutil.cpp:915
SynchronizationState
Current sync state passed to tip changed callbacks.
Definition: validation.h:93
void message(const QString &title, const QString &message, unsigned int style)
CClientUIInterface uiInterface
assert(!tx.IsCoinBase())
static int qt_argc
Definition: bitcoin.cpp:197
static bool isWalletEnabled()
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn&#39;t already have a value.
Definition: args.cpp:563
Class for the splashscreen with information of the running client.
Definition: splashscreen.h:26
Bilingual messages:
Definition: translation.h:24
void setNode(interfaces::Node &node)
bool noui_ThreadSafeMessageBox(const bilingual_str &message, unsigned int style)
Non-GUI handler, which logs and prints messages.
Definition: noui.cpp:22
static QString GetLangTerritory()
Definition: bitcoin.cpp:96
virtual bool baseInitialize()=0
Initialize app dependencies.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
void parameterSetup()
parameter interaction/setup based on rules
Definition: bitcoin.cpp:307
virtual void startShutdown()=0
Start shutdown.
void initialize()
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82
void handleRunawayException(const QString &message)
Handle runaway exceptions. Shows a message box with the problem and quits the program.
Definition: bitcoin.cpp:433
void SetPruneTargetGB(int prune_target_gb)
bool noui_ThreadSafeQuestion(const bilingual_str &, const std::string &message, unsigned int style)
Non-GUI handler, which logs and prints questions.
Definition: noui.cpp:49
void requestInitialize()
Request core initialization.
Definition: bitcoin.cpp:322
Failed to write settings.json.
void setClientModel(ClientModel *clientModel=nullptr, interfaces::BlockAndHeaderTipInfo *tip_info=nullptr)
Set the client model.
Definition: bitcoingui.cpp:664
Controller between interfaces::Node, WalletModel instances and the GUI.
OptionsModel * getOptionsModel()
SetupEnvironment()
Definition: system.cpp:64
void receivedPaymentRequest(SendCoinsRecipient)
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:177
std::string translated
Definition: translation.h:26
Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text repre...
Definition: guiutil.h:187
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:515
Bitcoin GUI main class.
Definition: bitcoingui.h:67
void shutdownResult()
std::unique_ptr< interfaces::Node > m_node
Definition: bitcoin.h:105
void noui_InitMessage(const std::string &message)
Non-GUI handler, which only logs a message.
Definition: noui.cpp:54
void handleNonFatalException(const QString &message)
A helper function that shows a message box with details about a non-fatal exception.
Definition: bitcoin.cpp:442
void requestedInitialize()
interfaces::Node & node() const
Definition: bitcoin.h:69
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition: exception.cpp:36
Qt event filter that intercepts QEvent::FocusOut events for QLabel objects, and resets their ‘textIn...
Definition: guiutil.h:207
static const bool DEFAULT_SPLASHSCREEN
Definition: guiconstants.h:25
static void ipcParseCommandLine(int argc, char *argv[])
static constexpr auto SHUTDOWN_POLLING_DELAY
Definition: guiconstants.h:17
disable validation
Definition: args.h:110
void InitPruneSetting(int64_t prune_MiB)
Initialize prune setting.
Definition: bitcoin.cpp:317
static bool ErrorSettingsRead(const bilingual_str &error, const std::vector< std::string > &details)
Definition: bitcoin.cpp:154
void handleURIOrFile(const QString &s)
void SetupServerArgs(ArgsManager &argsman, bool can_listen_ipc)
Register all arguments with the ArgsManager.
Definition: init.cpp:459
bool Init(bilingual_str &error)
static bool showIfNeeded(bool &did_show_intro, int64_t &prune_MiB)
Determine data directory.
Definition: intro.cpp:122
static bool ipcSendCommandLine()
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
static QWidget * showShutdownWindow(QMainWindow *window)
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:226
AddressPurpose
Address purpose field that has been been stored with wallet sending and receiving addresses since BIP...
Definition: types.h:28
bool GetSettingsPath(fs::path *filepath=nullptr, bool temp=false, bool backup=false) const
Get settings file path, or return false if read-write settings were disabled with -nosettings...
Definition: args.cpp:380
#define QAPP_ORG_NAME
Definition: guiconstants.h:49
static void RegisterMetaTypes()
Definition: bitcoin.cpp:75
void createNode(interfaces::Init &init)
Create or spawn node.
Definition: bitcoin.cpp:280
void createSplashScreen(const NetworkStyle *networkStyle)
Create splash screen.
Definition: bitcoin.cpp:273
virtual int getExitStatus()=0
Get exit status.
Main Bitcoin application object.
Definition: bitcoin.h:34
bool InitError(const bilingual_str &str)
Show error message.
#define LogInfo(...)
Definition: log.h:95
QT_END_NAMESPACE const QString BITCOIN_IPC_PREFIX
virtual bilingual_str getWarnings()=0
Get warnings.
void AddArg(const std::string &name, const std::string &help, unsigned int flags, const OptionsCategory &cat)
Add argument.
Definition: args.cpp:589
int GuiMain(int argc, char *argv[])
Definition: bitcoin.cpp:480
void detectShutdown()
called by a timer to check if shutdown has been requested
SplashScreen * m_splash
Definition: bitcoin.h:104
Block and header tip information.
Definition: node.h:49
static int PruneMiBtoGB(int64_t mib)
Convert configured prune target MiB to displayed GB.
Definition: optionsmodel.h:29
std::unique_ptr< QWidget > shutdownWindow
Definition: bitcoin.h:103
void windowShown(BitcoinGUI *window)
Model for Bitcoin network client.
Definition: clientmodel.h:56
is a home for public enum and struct type definitions that are used by internally by wallet code...
bool hasTrayIcon() const
Get the tray icon status.
Definition: bitcoingui.h:100
bool createOptionsModel(bool resetSettings)
Create options model.
Definition: bitcoin.cpp:238
SyncType
Definition: clientmodel.h:42
BitcoinGUI * window
Definition: bitcoin.h:96
void message(const QString &title, QString message, unsigned int style, bool *ret=nullptr, const QString &detailed_message=QString())
Notify the user of an event from the core network or transaction handling code.
void requestShutdown()
Request core shutdown.
Definition: bitcoin.cpp:329
ArgsManager gArgs
Definition: args.cpp:40
#define LogDebug(category,...)
Definition: log.h:115
static void SetupUIArgs(ArgsManager &argsman)
Definition: bitcoin.cpp:470
256-bit opaque blob.
Definition: uint256.h:195
#define QAPP_APP_NAME_DEFAULT
Definition: guiconstants.h:51
void createWindow(const NetworkStyle *networkStyle)
Create main window.
Definition: bitcoin.cpp:260
static const int TOOLTIP_WRAP_THRESHOLD
Definition: guiconstants.h:44
static const PlatformStyle * instantiate(const QString &platformId)
Get style associated with provided platform name, or 0 if not known.
std::string original
Definition: translation.h:25
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:42
#define QAPP_ORG_DOMAIN
Definition: guiconstants.h:50
const CChainParams & Params()
Return the currently selected parameters.
const QString & getName() const
Definition: platformstyle.h:19
bool getMinimizeToTray() const
Definition: optionsmodel.h:101
static auto quoted(const std::string &s)
Definition: fs.h:101
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:461
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:717
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:157
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
void LoadFont(const QString &file_name)
Loads the font from the file specified by file_name, aborts if it fails.
Definition: guiutil.cpp:291
static const char * qt_argv
Definition: bitcoin.cpp:198
QString MakeHtmlLink(const QString &source, const QString &link)
Replaces a plain text link with an HTML tagged one.
Definition: guiutil.cpp:960
"Help message" dialog box
Definition: utilitydialog.h:20
void ThreadSetInternalName(const std::string &)
Set the internal (in-memory) name of the current thread only.
Definition: threadnames.cpp:61
Initial interface created when a process is first started, and used to give and get access to other i...
Definition: init.h:30
static const NetworkStyle * instantiate(ChainType networkId)
Get style associated with provided network id, or 0 if not known.
std::unique_ptr< Init > MakeGuiInit(int argc, char *argv[])
Return implementation of Init interface for the gui process.
Definition: bitcoin-gui.cpp:50
static const std::string DEFAULT_UIPLATFORM
Definition: bitcoingui.h:72
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
void runawayException(const QString &message)
WId getMainWinId() const
Get window identifier of QMainWindow (BitcoinGUI)
Definition: bitcoin.cpp:452
std::optional< ConfigError > InitConfig(ArgsManager &args, SettingsAbortFn settings_abort_fn)
Definition: init.cpp:18
static RPCHelpMan help()
Definition: server.cpp:119
bool baseInitialize()
Basic initialization, before starting initialization/shutdown thread. Return true on success...
Definition: bitcoin.cpp:287
bool event(QEvent *e) override
Definition: bitcoin.cpp:460
ClientModel * clientModel
Definition: bitcoin.h:95
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition: init.cpp:764
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info)
Definition: bitcoin.cpp:379
std::optional< InitExecutor > m_executor
Definition: bitcoin.h:93
QTimer * pollShutdownTimer
Definition: bitcoin.h:97
const PlatformStyle * platformStyle
Definition: bitcoin.h:102