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