|
4 | 4 |
|
5 | 5 | #include <qml/bitcoin.h> |
6 | 6 |
|
| 7 | +#include <clientversion.h> |
| 8 | +#include <common/args.h> |
| 9 | +#include <common/init.h> |
| 10 | +#include <common/system.h> |
| 11 | +#include <init.h> |
| 12 | +#include <interfaces/init.h> |
| 13 | +#include <interfaces/node.h> |
| 14 | +#include <node/interface_ui.h> |
| 15 | +#include <noui.h> |
| 16 | +#include <qml/initexecutor.h> |
| 17 | +#include <qml/models/nodemodel.h> |
7 | 18 | #ifdef ENABLE_TEST_AUTOMATION |
8 | 19 | #include <qml/test/testbridge.h> |
9 | 20 | #endif |
| 21 | +#include <util/threadnames.h> |
| 22 | +#include <util/translation.h> |
10 | 23 |
|
11 | 24 | #include <QGuiApplication> |
12 | 25 | #include <QQmlApplicationEngine> |
| 26 | +#include <QQmlContext> |
13 | 27 | #include <QQuickStyle> |
14 | 28 | #include <QStringLiteral> |
| 29 | +#include <QTimer> |
15 | 30 | #include <QUrl> |
16 | 31 |
|
17 | 32 | #include <cstdlib> |
| 33 | +#include <iostream> |
18 | 34 | #include <memory> |
19 | | - |
20 | | -#ifdef ENABLE_TEST_AUTOMATION |
21 | | -namespace { |
22 | | -QString TestAutomationSocketPath(int argc, char* argv[]) |
23 | | -{ |
24 | | - const QString prefix{QStringLiteral("-test-automation=")}; |
25 | | - for (int i = 1; i < argc; ++i) { |
26 | | - const QString argument{QString::fromLocal8Bit(argv[i])}; |
27 | | - if (argument.startsWith(prefix)) { |
28 | | - return argument.sliced(prefix.size()); |
29 | | - } |
30 | | - } |
31 | | - return {}; |
32 | | -} |
33 | | -} // namespace |
34 | | -#endif |
| 35 | +#include <string> |
| 36 | +#include <tuple> |
35 | 37 |
|
36 | 38 | int QmlGuiMain(int argc, char* argv[]) |
37 | 39 | { |
38 | 40 | Q_INIT_RESOURCE(bitcoin_qml); |
39 | 41 |
|
| 42 | +#ifdef WIN32 |
| 43 | + common::WinCmdLineArgs win_args; |
| 44 | + std::tie(argc, argv) = win_args.get(); |
| 45 | +#endif |
| 46 | + |
40 | 47 | QQuickStyle::setStyle(QStringLiteral("Basic")); |
41 | 48 |
|
42 | 49 | QGuiApplication app(argc, argv); |
43 | 50 | QGuiApplication::setApplicationDisplayName(QGuiApplication::translate("bitcoin-core", "Bitcoin Core")); |
| 51 | + QGuiApplication::setQuitOnLastWindowClosed(false); |
| 52 | + |
| 53 | + SetupEnvironment(); |
| 54 | + util::ThreadSetInternalName("main"); |
| 55 | + noui_connect(); |
| 56 | + |
| 57 | + std::unique_ptr<interfaces::Init> init{interfaces::MakeGuiInit(argc, argv)}; |
| 58 | + |
| 59 | + SetupServerArgs(gArgs, init->canListenIpc()); |
| 60 | +#ifdef ENABLE_TEST_AUTOMATION |
| 61 | + gArgs.AddArg("-test-automation=<path>", "Enable test automation bridge on the given local socket path", ArgsManager::ALLOW_ANY, OptionsCategory::GUI); |
| 62 | +#endif |
| 63 | + std::string error; |
| 64 | + if (!gArgs.ParseParameters(argc, argv, error)) { |
| 65 | + InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error))); |
| 66 | + return EXIT_FAILURE; |
| 67 | + } |
| 68 | + |
| 69 | + if (HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) { |
| 70 | + std::cout << init->exeName() << " " << FormatFullVersion() << "\n"; |
| 71 | + if (!gArgs.GetBoolArg("-version", false)) { |
| 72 | + std::cout << "\n" << gArgs.GetHelpMessage(); |
| 73 | + } |
| 74 | + return EXIT_SUCCESS; |
| 75 | + } |
| 76 | + |
| 77 | + for (int i = 1; i < argc; ++i) { |
| 78 | + if (!IsSwitchChar(argv[i][0])) { |
| 79 | + InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoin-qml -h for a list of options.", argv[i]))); |
| 80 | + return EXIT_FAILURE; |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + if (auto config_error{common::InitConfig(gArgs)}) { |
| 85 | + InitError(config_error->message, config_error->details); |
| 86 | + return EXIT_FAILURE; |
| 87 | + } |
| 88 | + |
| 89 | + gArgs.SoftSetBoolArg("-printtoconsole", false); |
| 90 | + InitLogging(gArgs); |
| 91 | + InitParameterInteraction(gArgs); |
| 92 | + |
| 93 | + std::unique_ptr<interfaces::Node> node{init->makeNode()}; |
| 94 | + if (!node->baseInitialize()) { |
| 95 | + return EXIT_FAILURE; |
| 96 | + } |
| 97 | + |
| 98 | + qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo"); |
| 99 | + |
| 100 | + NodeModel node_model{*node}; |
| 101 | + QmlInitExecutor init_executor{*node}; |
| 102 | + |
| 103 | + QObject::connect(&node_model, &NodeModel::requestedInitialize, &init_executor, &QmlInitExecutor::initialize); |
| 104 | + QObject::connect(&node_model, &NodeModel::requestedShutdown, &init_executor, &QmlInitExecutor::shutdown); |
| 105 | + QObject::connect(&init_executor, &QmlInitExecutor::initializeResult, &node_model, &NodeModel::initializeResult); |
| 106 | + QObject::connect(&init_executor, &QmlInitExecutor::shutdownResult, &node_model, &NodeModel::shutdownResult); |
| 107 | + QObject::connect(&init_executor, &QmlInitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException); |
| 108 | + QObject::connect(&node_model, &NodeModel::shutdownComplete, &app, [&app, &node] { |
| 109 | + app.exit(node->getExitStatus()); |
| 110 | + }); |
| 111 | + QObject::connect(&app, &QGuiApplication::lastWindowClosed, &node_model, &NodeModel::requestShutdown); |
44 | 112 |
|
45 | 113 | QQmlApplicationEngine engine; |
| 114 | + engine.rootContext()->setContextProperty(QStringLiteral("nodeModel"), &node_model); |
46 | 115 | engine.load(QUrl{QStringLiteral("qrc:///qml/pages/MainWindow.qml")}); |
47 | 116 | if (engine.rootObjects().isEmpty()) { |
| 117 | + node->startShutdown(); |
| 118 | + node->appShutdown(); |
48 | 119 | return EXIT_FAILURE; |
49 | 120 | } |
50 | 121 |
|
51 | 122 | #ifdef ENABLE_TEST_AUTOMATION |
52 | 123 | std::unique_ptr<TestBridge> test_bridge; |
53 | | - if (const QString socket_path{TestAutomationSocketPath(argc, argv)}; !socket_path.isEmpty()) { |
54 | | - test_bridge = std::make_unique<TestBridge>(engine, socket_path); |
| 124 | + if (gArgs.IsArgSet("-test-automation")) { |
| 125 | + const QString socket_path{QString::fromStdString(gArgs.GetArg("-test-automation", ""))}; |
| 126 | + if (!socket_path.isEmpty()) { |
| 127 | + test_bridge = std::make_unique<TestBridge>(engine, socket_path); |
| 128 | + } |
55 | 129 | } |
56 | 130 | #endif |
57 | 131 |
|
| 132 | + QTimer::singleShot(0, &node_model, &NodeModel::start); |
58 | 133 | return app.exec(); |
59 | 134 | } |
0 commit comments