Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <csignal>
24 :
25 : #include <QApplication>
26 : #include <QStyleHints>
27 : #include <QQuickWindow>
28 : #include <QSslSocket>
29 :
30 : #include "appfactory.h"
31 : #include "internal/commandlineparser.h"
32 : #include "global/iapplication.h"
33 :
34 : #include "muse_framework_config.h"
35 : #include "app_config.h"
36 :
37 : #include "log.h"
38 :
39 : // C++20 check
40 : // #include <concepts>
41 : // #include <type_traits>
42 : // consteval int square(int n) { return n * n; }
43 : // static_assert(square(5) == 25);
44 : // ========================
45 :
46 : #ifndef MUSE_MODULE_DIAGNOSTICS_CRASHPAD_CLIENT
47 0 : static void crashCallback(int signum)
48 : {
49 0 : const char* signame = "UNKNOWN SIGNAME";
50 0 : const char* sigdescript = "";
51 0 : switch (signum) {
52 0 : case SIGILL:
53 0 : signame = "SIGILL";
54 0 : sigdescript = "Illegal Instruction";
55 0 : break;
56 0 : case SIGSEGV:
57 0 : signame = "SIGSEGV";
58 0 : sigdescript = "Invalid memory reference";
59 0 : break;
60 : }
61 0 : LOGE() << "Oops! Application crashed with signal: [" << signum << "] " << signame << "-" << sigdescript;
62 0 : exit(EXIT_FAILURE);
63 : }
64 :
65 : #endif
66 :
67 0 : static void app_init_qrc()
68 : {
69 0 : Q_INIT_RESOURCE(app);
70 :
71 : #ifdef Q_OS_WIN
72 : Q_INIT_RESOURCE(app_win);
73 : #endif
74 0 : }
75 :
76 0 : int main(int argc, char** argv)
77 : {
78 : #ifndef MUSE_MODULE_DIAGNOSTICS_CRASHPAD_CLIENT
79 0 : signal(SIGSEGV, crashCallback);
80 0 : signal(SIGILL, crashCallback);
81 0 : signal(SIGFPE, crashCallback);
82 : #endif
83 :
84 : // ====================================================
85 : // Setup global Qt application variables
86 : // ====================================================
87 :
88 0 : app_init_qrc();
89 :
90 0 : qputenv("QT_STYLE_OVERRIDE", "Fusion");
91 0 : qputenv("QML_DISABLE_DISK_CACHE", "true");
92 :
93 : // HACK: Workaround for crash #28840. This disables the incremental GC
94 0 : if (!qEnvironmentVariableIsSet("MU_QV4_GC_TIMELIMIT")) {
95 0 : qputenv("QV4_GC_TIMELIMIT", "0");
96 : }
97 :
98 0 : if (!qEnvironmentVariableIsSet("QT_QUICK_FLICKABLE_WHEEL_DECELERATION")) {
99 0 : qputenv("QT_QUICK_FLICKABLE_WHEEL_DECELERATION", "5000");
100 : }
101 :
102 : #ifdef Q_OS_LINUX
103 0 : if (qEnvironmentVariable("MU_QT_QPA_PLATFORM") != "offscreen") {
104 0 : qputenv("QT_QPA_PLATFORMTHEME", "gtk3");
105 : }
106 :
107 : //! NOTE Forced X11, with Wayland there are a number of problems now
108 0 : if (qEnvironmentVariable("MU_QT_QPA_PLATFORM") == "") {
109 0 : qputenv("QT_QPA_PLATFORM", "xcb");
110 : }
111 : #endif
112 :
113 : #ifdef Q_OS_WIN
114 : // NOTE: There are some problems with rendering the application window on some integrated graphics processors
115 : // see https://github.com/musescore/MuseScore/issues/8270
116 : if (!qEnvironmentVariableIsSet("QT_OPENGL_BUGLIST")) {
117 : qputenv("QT_OPENGL_BUGLIST", ":/resources/win_opengl_buglist.json");
118 : }
119 : #endif
120 :
121 0 : QGuiApplication::styleHints()->setMousePressAndHoldInterval(250);
122 :
123 : #ifdef MUSE_APP_UNSTABLE
124 0 : QCoreApplication::setApplicationName(MUSE_APP_NAME_MACHINE_READABLE MUSE_APP_VERSION_MAJOR "Development");
125 : #else
126 : QCoreApplication::setApplicationName(MUSE_APP_NAME_MACHINE_READABLE MUSE_APP_VERSION_MAJOR);
127 : #endif
128 0 : QCoreApplication::setOrganizationName("MuseScore");
129 0 : QCoreApplication::setOrganizationDomain("musescore.org");
130 0 : QCoreApplication::setApplicationVersion(MUSE_APP_VERSION);
131 :
132 : #if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) && !defined(Q_OS_WASM)
133 : // Any OS that uses Freedesktop.org Desktop Entry Specification (e.g. Linux, BSD)
134 : #ifndef MUSE_APP_INSTALL_SUFFIX
135 : #define MUSE_APP_INSTALL_SUFFIX ""
136 : #endif
137 0 : QGuiApplication::setDesktopFileName("org.musescore.MuseScore" MUSE_APP_INSTALL_SUFFIX);
138 : #endif
139 :
140 : using namespace muse;
141 : using namespace mu::app;
142 :
143 0 : auto fixSslBackend = []() {
144 : #ifdef Q_OS_WIN
145 : // NOTE: Force schannel backend. Qt prefers OpenSSL when qopensslbackend.dll
146 : // is present, which can crash on ABI mismatch with bundled OpenSSL.
147 : // see https://github.com/musescore/MuseScore/issues/33401
148 : QSslSocket::setActiveBackend("schannel");
149 : #endif
150 0 : };
151 :
152 : // ====================================================
153 : // Parse command line options
154 : // ====================================================
155 : #ifdef MUE_ENABLE_CONSOLEAPP
156 0 : CommandLineParser commandLineParser;
157 0 : commandLineParser.init();
158 0 : commandLineParser.parse(argc, argv);
159 :
160 0 : IApplication::RunMode runMode = commandLineParser.runMode();
161 0 : QCoreApplication* qapp = nullptr;
162 :
163 0 : if (runMode == IApplication::RunMode::AudioPluginRegistration) {
164 0 : qapp = new QCoreApplication(argc, argv);
165 : } else {
166 0 : qapp = new QApplication(argc, argv);
167 : }
168 :
169 0 : fixSslBackend();
170 :
171 0 : commandLineParser.processBuiltinArgs(*qapp);
172 0 : std::shared_ptr<MuseScoreCmdOptions> opt = commandLineParser.options();
173 :
174 : #else
175 : QCoreApplication* qapp = new QApplication(argc, argv);
176 :
177 : fixSslBackend();
178 :
179 : std::shared_ptr<MuseScoreCmdOptions> opt = std::make_shared<MuseScoreCmdOptions>();
180 : opt->runMode = IApplication::RunMode::GuiApp;
181 : #endif
182 :
183 : // ====================================================
184 : // Setup application
185 : // ====================================================
186 :
187 : //! NOTE: We immediately launch the application's event loop
188 : // to be able to show a splash screen (on Linux, splash screen won't show without event loop).
189 : // All subsequent initialization steps will be executed as events in the event loop.
190 :
191 0 : std::shared_ptr<muse::IApplication> app;
192 0 : QMetaObject::invokeMethod(qapp, [qapp, &app, &opt]() {
193 : AppFactory f;
194 0 : app = f.newApp(opt);
195 0 : IF_ASSERT_FAILED(app) {
196 0 : return;
197 : }
198 0 : app->showSplash();
199 0 : QMetaObject::invokeMethod(qapp, [qapp, &app]() {
200 0 : app->setup();
201 0 : QMetaObject::invokeMethod(qapp, [&app]() {
202 0 : app->setupNewContext();
203 :
204 0 : LOGI() << QString("SSL Info: supported: %1, build: %2, runtime: %3, active backend: %4, available backends: %5")
205 0 : .arg(QSslSocket::supportsSsl())
206 0 : .arg(QSslSocket::sslLibraryBuildVersionString())
207 0 : .arg(QSslSocket::sslLibraryVersionString())
208 0 : .arg(QSslSocket::activeBackend())
209 0 : .arg(QSslSocket::availableBackends().join(", "));
210 0 : }, Qt::QueuedConnection);
211 0 : }, Qt::QueuedConnection);
212 : }, Qt::QueuedConnection);
213 :
214 : // ====================================================
215 : // Run main loop
216 : // ====================================================
217 0 : int code = qapp->exec();
218 :
219 : // ====================================================
220 : // Quit
221 : // ====================================================
222 :
223 0 : if (app) {
224 0 : app->finish();
225 : }
226 :
227 0 : delete qapp;
228 :
229 0 : LOGI() << "Goodbye!! code: " << code;
230 0 : return code;
231 0 : }
|