1/****************************************************************************
2**
3** Copyright (C) 2016 Research In Motion.
4** Copyright (C) 2019 The Qt Company Ltd.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include "conf.h"
31
32#include <QCoreApplication>
33
34#ifdef QT_GUI_LIB
35#include <QGuiApplication>
36#include <QWindow>
37#include <QFileOpenEvent>
38#include <QOpenGLContext>
39#include <QOpenGLFunctions>
40#include <QSurfaceFormat>
41#ifdef QT_WIDGETS_LIB
42#include <QApplication>
43#endif // QT_WIDGETS_LIB
44#endif // QT_GUI_LIB
45
46#include <QQmlApplicationEngine>
47#include <QQmlComponent>
48#include <QCommandLineOption>
49#include <QCommandLineParser>
50#include <QDir>
51#include <QFile>
52#include <QFileInfo>
53#include <QLoggingCategory>
54#include <QStringList>
55#include <QScopedPointer>
56#include <QDebug>
57#include <QStandardPaths>
58#include <QTranslator>
59#include <QtGlobal>
60#include <QLibraryInfo>
61#include <qqml.h>
62#include <qqmldebug.h>
63#include <qqmlfileselector.h>
64
65#include <private/qmemory_p.h>
66#include <private/qtqmlglobal_p.h>
67#if QT_CONFIG(qml_animation)
68#include <private/qabstractanimation_p.h>
69#endif
70
71#include <cstdio>
72#include <cstring>
73#include <cstdlib>
74#include <memory>
75
76#define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms
77
78enum QmlApplicationType {
79 QmlApplicationTypeUnknown
80 , QmlApplicationTypeCore
81#ifdef QT_GUI_LIB
82 , QmlApplicationTypeGui
83#ifdef QT_WIDGETS_LIB
84 , QmlApplicationTypeWidget
85#endif // QT_WIDGETS_LIB
86#endif // QT_GUI_LIB
87};
88
89static QmlApplicationType applicationType =
90#ifndef QT_GUI_LIB
91 QmlApplicationTypeCore;
92#else
93 QmlApplicationTypeGui;
94#endif // QT_GUI_LIB
95
96static Config *conf = nullptr;
97static QQmlApplicationEngine *qae = nullptr;
98#if defined(Q_OS_DARWIN) || defined(QT_GUI_LIB)
99static int exitTimerId = -1;
100#endif
101static const QString iconResourcePath(QStringLiteral(":/qt-project.org/QmlRuntime/resources/qml-64.png"));
102static const QString confResourcePath(QStringLiteral(":/qt-project.org/QmlRuntime/conf/"));
103static bool verboseMode = false;
104static bool quietMode = false;
105
106static void loadConf(const QString &override, bool quiet) // Terminates app on failure
107{
108 const QString defaultFileName = QLatin1String("default.qml");
109 QUrl settingsUrl;
110 bool builtIn = false; //just for keeping track of the warning
111 if (override.isEmpty()) {
112 QFileInfo fi;
113 fi.setFile(QStandardPaths::locate(type: QStandardPaths::DataLocation, fileName: defaultFileName));
114 if (fi.exists()) {
115 settingsUrl = QUrl::fromLocalFile(localfile: fi.absoluteFilePath());
116 } else {
117 // ### If different built-in configs are needed per-platform, just apply QFileSelector to the qrc conf.qml path
118 fi.setFile(confResourcePath + defaultFileName);
119 settingsUrl = QUrl::fromLocalFile(localfile: fi.absoluteFilePath());
120 builtIn = true;
121 }
122 } else {
123 QFileInfo fi;
124 fi.setFile(confResourcePath + override + QLatin1String(".qml"));
125 if (fi.exists()) {
126 settingsUrl = QUrl::fromLocalFile(localfile: fi.absoluteFilePath());
127 builtIn = true;
128 } else {
129 fi.setFile(override);
130 if (!fi.exists()) {
131 printf(format: "qml: Couldn't find required configuration file: %s\n",
132 qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
133 exit(status: 1);
134 }
135 settingsUrl = QUrl::fromLocalFile(localfile: fi.absoluteFilePath());
136 }
137 }
138
139 if (!quiet) {
140 printf(format: "qml: %s\n", QLibraryInfo::build());
141 if (builtIn) {
142 printf(format: "qml: Using built-in configuration: %s\n",
143 qPrintable(override.isEmpty() ? defaultFileName : override));
144 } else {
145 printf(format: "qml: Using configuration: %s\n",
146 qPrintable(settingsUrl.isLocalFile()
147 ? QDir::toNativeSeparators(settingsUrl.toLocalFile())
148 : settingsUrl.toString()));
149 }
150 }
151
152 // TODO: When we have better engine control, ban QtQuick* imports on this engine
153 QQmlEngine e2;
154 QQmlComponent c2(&e2, settingsUrl);
155 conf = qobject_cast<Config*>(object: c2.create());
156
157 if (!conf){
158 printf(format: "qml: Error loading configuration file: %s\n", qPrintable(c2.errorString()));
159 exit(status: 1);
160 }
161}
162
163void noFilesGiven()
164{
165 if (!quietMode)
166 printf(format: "qml: No files specified. Terminating.\n");
167 exit(status: 1);
168}
169
170static void listConfFiles()
171{
172 QDir confResourceDir(confResourcePath);
173 printf(format: "%s\n", qPrintable(QCoreApplication::translate("main", "Built-in configurations:")));
174 for (const QFileInfo &fi : confResourceDir.entryInfoList(filters: QDir::Files))
175 printf(format: " %s\n", qPrintable(fi.baseName()));
176 exit(status: 0);
177}
178
179#ifdef QT_GUI_LIB
180
181// Loads qml after receiving a QFileOpenEvent
182class LoaderApplication : public QGuiApplication
183{
184public:
185 LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv)
186 {
187 setWindowIcon(QIcon(iconResourcePath));
188 }
189
190 bool event(QEvent *ev) override
191 {
192 if (ev->type() == QEvent::FileOpen) {
193 if (exitTimerId >= 0) {
194 killTimer(id: exitTimerId);
195 exitTimerId = -1;
196 }
197 qae->load(url: static_cast<QFileOpenEvent *>(ev)->url());
198 }
199 else
200 return QGuiApplication::event(ev);
201 return true;
202 }
203
204 void timerEvent(QTimerEvent *) override {
205 noFilesGiven();
206 }
207};
208
209#endif // QT_GUI_LIB
210
211// Listens to the appEngine signals to determine if all files failed to load
212class LoadWatcher : public QObject
213{
214 Q_OBJECT
215public:
216 LoadWatcher(QQmlApplicationEngine *e, int expected)
217 : QObject(e)
218 , expectedFileCount(expected)
219 {
220 connect(sender: e, signal: &QQmlApplicationEngine::objectCreated, receiver: this, slot: &LoadWatcher::checkFinished);
221 // QQmlApplicationEngine also connects quit() to QCoreApplication::quit
222 // and exit() to QCoreApplication::exit but if called before exec()
223 // then QCoreApplication::quit or QCoreApplication::exit does nothing
224 connect(sender: e, signal: &QQmlEngine::quit, receiver: this, slot: &LoadWatcher::quit);
225 connect(sender: e, signal: &QQmlEngine::exit, receiver: this, slot: &LoadWatcher::exit);
226 }
227
228 int returnCode = 0;
229 bool earlyExit = false;
230
231public Q_SLOTS:
232 void checkFinished(QObject *o, const QUrl &url)
233 {
234 Q_UNUSED(url)
235 if (o) {
236 checkForWindow(o);
237 if (conf && qae)
238 for (PartialScene *ps : qAsConst(t&: conf->completers))
239 if (o->inherits(classname: ps->itemType().toUtf8().constData()))
240 contain(o, containPath: ps->container());
241 }
242 if (haveWindow)
243 return;
244
245 if (! --expectedFileCount) {
246 printf(format: "qml: Did not load any objects, exiting.\n");
247 std::exit(status: 2); // Different return code from qFatal
248 }
249 }
250
251 void quit() {
252 // Will be checked before calling exec()
253 earlyExit = true;
254 returnCode = 0;
255 }
256 void exit(int retCode) {
257 earlyExit = true;
258 returnCode = retCode;
259 }
260
261#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
262 void onOpenGlContextCreated(QOpenGLContext *context);
263#endif
264
265private:
266 void contain(QObject *o, const QUrl &containPath);
267 void checkForWindow(QObject *o);
268
269private:
270 bool haveWindow = false;
271 int expectedFileCount;
272};
273
274void LoadWatcher::contain(QObject *o, const QUrl &containPath)
275{
276 QQmlComponent c(qae, containPath);
277 QObject *o2 = c.create();
278 if (!o2)
279 return;
280 checkForWindow(o: o2);
281 bool success = false;
282 int idx;
283 if ((idx = o2->metaObject()->indexOfProperty(name: "containedObject")) != -1)
284 success = o2->metaObject()->property(index: idx).write(obj: o2, value: QVariant::fromValue<QObject*>(value: o));
285 if (!success)
286 o->setParent(o2); // Set QObject parent, and assume container will react as needed
287}
288
289void LoadWatcher::checkForWindow(QObject *o)
290{
291#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
292 if (o->isWindowType() && o->inherits(classname: "QQuickWindow")) {
293 haveWindow = true;
294 if (verboseMode)
295 connect(sender: o, SIGNAL(openglContextCreated(QOpenGLContext*)),
296 receiver: this, SLOT(onOpenGlContextCreated(QOpenGLContext*)));
297 }
298#else
299 Q_UNUSED(o)
300#endif // QT_GUI_LIB && !QT_NO_OPENGL
301}
302
303#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
304void LoadWatcher::onOpenGlContextCreated(QOpenGLContext *context)
305{
306 context->makeCurrent(surface: qobject_cast<QWindow *>(o: sender()));
307 QOpenGLFunctions functions(context);
308 QByteArray output = "Vendor : ";
309 output += reinterpret_cast<const char *>(functions.glGetString(GL_VENDOR));
310 output += "\nRenderer: ";
311 output += reinterpret_cast<const char *>(functions.glGetString(GL_RENDERER));
312 output += "\nVersion : ";
313 output += reinterpret_cast<const char *>(functions.glGetString(GL_VERSION));
314 output += "\nLanguage: ";
315 output += reinterpret_cast<const char *>(functions.glGetString(GL_SHADING_LANGUAGE_VERSION));
316 puts(s: output.constData());
317 context->doneCurrent();
318}
319#endif // QT_GUI_LIB && !QT_NO_OPENGL
320
321void quietMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg)
322{
323 Q_UNUSED(ctxt);
324 Q_UNUSED(msg);
325 // Doesn't print anything
326 switch (type) {
327 case QtFatalMsg:
328 exit(status: -1);
329 case QtCriticalMsg:
330 case QtDebugMsg:
331 case QtInfoMsg:
332 case QtWarningMsg:
333 ;
334 }
335}
336
337// Called before application initialization
338static void getAppFlags(int argc, char **argv)
339{
340#ifdef QT_GUI_LIB
341 for (int i=0; i<argc; i++) {
342 if (!strcmp(s1: argv[i], s2: "--apptype") || !strcmp(s1: argv[i], s2: "-a") || !strcmp(s1: argv[i], s2: "-apptype")) {
343 applicationType = QmlApplicationTypeUnknown;
344 if (i+1 < argc) {
345 ++i;
346 if (!strcmp(s1: argv[i], s2: "core"))
347 applicationType = QmlApplicationTypeCore;
348 else if (!strcmp(s1: argv[i], s2: "gui"))
349 applicationType = QmlApplicationTypeGui;
350# ifdef QT_WIDGETS_LIB
351 else if (!strcmp(s1: argv[i], s2: "widget"))
352 applicationType = QmlApplicationTypeWidget;
353# endif // QT_WIDGETS_LIB
354
355 }
356 } else if (!strcmp(s1: argv[i], s2: "-desktop") || !strcmp(s1: argv[i], s2: "--desktop")) {
357 QCoreApplication::setAttribute(attribute: Qt::AA_UseDesktopOpenGL);
358 } else if (!strcmp(s1: argv[i], s2: "-gles") || !strcmp(s1: argv[i], s2: "--gles")) {
359 QCoreApplication::setAttribute(attribute: Qt::AA_UseOpenGLES);
360 } else if (!strcmp(s1: argv[i], s2: "-software") || !strcmp(s1: argv[i], s2: "--software")) {
361 QCoreApplication::setAttribute(attribute: Qt::AA_UseSoftwareOpenGL);
362 } else if (!strcmp(s1: argv[i], s2: "-scaling") || !strcmp(s1: argv[i], s2: "--scaling")) {
363 QCoreApplication::setAttribute(attribute: Qt::AA_EnableHighDpiScaling);
364 } else if (!strcmp(s1: argv[i], s2: "-no-scaling") || !strcmp(s1: argv[i], s2: "--no-scaling")) {
365 QCoreApplication::setAttribute(attribute: Qt::AA_DisableHighDpiScaling);
366 }
367 }
368#else
369 Q_UNUSED(argc)
370 Q_UNUSED(argv)
371#endif // QT_GUI_LIB
372}
373
374bool getFileSansBangLine(const QString &path, QByteArray &output)
375{
376 QFile f(path);
377 if (!f.open(flags: QFile::ReadOnly | QFile::Text))
378 return false;
379 output = f.readAll();
380 if (output.startsWith(c: "#!")) {//Remove first line in this case (except \n, to avoid disturbing line count)
381 output.remove(index: 0, len: output.indexOf(c: '\n'));
382 return true;
383 }
384 return false;
385}
386
387static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
388{
389 QDir dir(directory+"/dummydata", "*.qml");
390 QStringList list = dir.entryList();
391 for (int i = 0; i < list.size(); ++i) {
392 QString qml = list.at(i);
393 QQmlComponent comp(&engine, dir.filePath(fileName: qml));
394 QObject *dummyData = comp.create();
395
396 if (comp.isError()) {
397 const QList<QQmlError> errors = comp.errors();
398 for (const QQmlError &error : errors)
399 qWarning() << error;
400 }
401
402 if (dummyData && !quietMode) {
403 printf(format: "qml: Loaded dummy data: %s\n", qPrintable(dir.filePath(qml)));
404 qml.truncate(pos: qml.length()-4);
405 engine.rootContext()->setContextProperty(qml, dummyData);
406 dummyData->setParent(&engine);
407 }
408 }
409}
410
411int main(int argc, char *argv[])
412{
413 getAppFlags(argc, argv);
414 std::unique_ptr<QCoreApplication> app;
415 switch (applicationType) {
416#ifdef QT_GUI_LIB
417 case QmlApplicationTypeGui:
418 app = qt_make_unique<LoaderApplication>(args&: argc, args&: argv);
419 break;
420#ifdef QT_WIDGETS_LIB
421 case QmlApplicationTypeWidget:
422 app = qt_make_unique<QApplication>(args&: argc, args&: argv);
423 static_cast<QApplication *>(app.get())->setWindowIcon(QIcon(iconResourcePath));
424 break;
425#endif // QT_WIDGETS_LIB
426#endif // QT_GUI_LIB
427 case QmlApplicationTypeCore:
428 Q_FALLTHROUGH();
429 default: // QmlApplicationTypeUnknown: not allowed, but we'll exit after checking apptypeOption below
430 app = qt_make_unique<QCoreApplication>(args&: argc, args&: argv);
431 break;
432 }
433
434 app->setApplicationName("Qml Runtime");
435 app->setOrganizationName("QtProject");
436 app->setOrganizationDomain("qt-project.org");
437 QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
438
439 QQmlApplicationEngine e;
440 QStringList files;
441 QString confFile;
442 QString translationFile;
443 QString dummyDir;
444
445 // Handle main arguments
446 QCommandLineParser parser;
447 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
448 parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments);
449 const QCommandLineOption helpOption = parser.addHelpOption();
450 const QCommandLineOption versionOption = parser.addVersionOption();
451#ifdef QT_GUI_LIB
452 QCommandLineOption apptypeOption(QStringList() << QStringLiteral("a") << QStringLiteral("apptype"),
453 QCoreApplication::translate(context: "main", key: "Select which application class to use. Default is gui."),
454#ifdef QT_WIDGETS_LIB
455 QStringLiteral("core|gui|widget"));
456#else
457 QStringLiteral("core|gui"));
458#endif // QT_WIDGETS_LIB
459 parser.addOption(commandLineOption: apptypeOption); // Just for the help text... we've already handled this argument above
460#endif // QT_GUI_LIB
461 QCommandLineOption importOption(QStringLiteral("I"),
462 QCoreApplication::translate(context: "main", key: "Prepend the given path to the import paths."), QStringLiteral("path"));
463 parser.addOption(commandLineOption: importOption);
464 QCommandLineOption qmlFileOption(QStringLiteral("f"),
465 QCoreApplication::translate(context: "main", key: "Load the given file as a QML file."), QStringLiteral("file"));
466 parser.addOption(commandLineOption: qmlFileOption);
467 QCommandLineOption configOption(QStringList() << QStringLiteral("c") << QStringLiteral("config"),
468 QCoreApplication::translate(context: "main", key: "Load the given built-in configuration or configuration file."), QStringLiteral("file"));
469 parser.addOption(commandLineOption: configOption);
470 QCommandLineOption listConfOption(QStringList() << QStringLiteral("list-conf"),
471 QCoreApplication::translate(context: "main", key: "List the built-in configurations."));
472 parser.addOption(commandLineOption: listConfOption);
473 QCommandLineOption translationOption(QStringLiteral("translation"),
474 QCoreApplication::translate(context: "main", key: "Load the given file as the translations file."), QStringLiteral("file"));
475 parser.addOption(commandLineOption: translationOption);
476 QCommandLineOption dummyDataOption(QStringLiteral("dummy-data"),
477 QCoreApplication::translate(context: "main", key: "Load QML files from the given directory as context properties."), QStringLiteral("file"));
478 parser.addOption(commandLineOption: dummyDataOption);
479#ifdef QT_GUI_LIB
480 // OpenGL options
481 QCommandLineOption glDesktopOption(QStringLiteral("desktop"),
482 QCoreApplication::translate(context: "main", key: "Force use of desktop OpenGL (AA_UseDesktopOpenGL)."));
483 parser.addOption(commandLineOption: glDesktopOption); // Just for the help text... we've already handled this argument above
484 QCommandLineOption glEsOption(QStringLiteral("gles"),
485 QCoreApplication::translate(context: "main", key: "Force use of GLES (AA_UseOpenGLES)."));
486 parser.addOption(commandLineOption: glEsOption); // Just for the help text... we've already handled this argument above
487 QCommandLineOption glSoftwareOption(QStringLiteral("software"),
488 QCoreApplication::translate(context: "main", key: "Force use of software rendering (AA_UseSoftwareOpenGL)."));
489 parser.addOption(commandLineOption: glSoftwareOption); // Just for the help text... we've already handled this argument above
490 QCommandLineOption scalingOption(QStringLiteral("scaling"),
491 QCoreApplication::translate(context: "main", key: "Enable High DPI scaling (AA_EnableHighDpiScaling)."));
492 parser.addOption(commandLineOption: scalingOption); // Just for the help text... we've already handled this argument above
493 QCommandLineOption noScalingOption(QStringLiteral("no-scaling"),
494 QCoreApplication::translate(context: "main", key: "Disable High DPI scaling (AA_DisableHighDpiScaling)."));
495 parser.addOption(commandLineOption: noScalingOption); // Just for the help text... we've already handled this argument above
496#endif // QT_GUI_LIB
497 // Debugging and verbosity options
498 QCommandLineOption quietOption(QStringLiteral("quiet"),
499 QCoreApplication::translate(context: "main", key: "Suppress all output."));
500 parser.addOption(commandLineOption: quietOption);
501 QCommandLineOption verboseOption(QStringLiteral("verbose"),
502 QCoreApplication::translate(context: "main", key: "Print information about what qml is doing, like specific file URLs being loaded."));
503 parser.addOption(commandLineOption: verboseOption);
504 QCommandLineOption slowAnimationsOption(QStringLiteral("slow-animations"),
505 QCoreApplication::translate(context: "main", key: "Run all animations in slow motion."));
506 parser.addOption(commandLineOption: slowAnimationsOption);
507 QCommandLineOption fixedAnimationsOption(QStringLiteral("fixed-animations"),
508 QCoreApplication::translate(context: "main", key: "Run animations off animation tick rather than wall time."));
509 parser.addOption(commandLineOption: fixedAnimationsOption);
510 QCommandLineOption rhiOption(QStringList() << QStringLiteral("r") << QStringLiteral("rhi"),
511 QCoreApplication::translate(context: "main", key: "Use the Qt graphics abstraction (RHI) instead of OpenGL directly. "
512 "Backend is one of: default, vulkan, metal, d3d11, gl"),
513 QStringLiteral("backend"));
514 parser.addOption(commandLineOption: rhiOption);
515 QCommandLineOption selectorOption(QStringLiteral("S"), QCoreApplication::translate(context: "main",
516 key: "Add selector to the list of QQmlFileSelectors."), QStringLiteral("selector"));
517 parser.addOption(commandLineOption: selectorOption);
518
519 // Positional arguments
520 parser.addPositionalArgument(name: "files",
521 description: QCoreApplication::translate(context: "main", key: "Any number of QML files can be loaded. They will share the same engine."), syntax: "[files...]");
522 parser.addPositionalArgument(name: "args",
523 description: QCoreApplication::translate(context: "main", key: "Arguments after '--' are ignored, but passed through to the application.arguments variable in QML."), syntax: "[-- args...]");
524
525 if (!parser.parse(arguments: QCoreApplication::arguments())) {
526 qWarning() << parser.errorText();
527 exit(status: 1);
528 }
529 if (parser.isSet(option: versionOption))
530 parser.showVersion();
531 if (parser.isSet(option: helpOption))
532 parser.showHelp();
533 if (parser.isSet(option: listConfOption))
534 listConfFiles();
535 if (applicationType == QmlApplicationTypeUnknown) {
536#ifdef QT_WIDGETS_LIB
537 qWarning() << QCoreApplication::translate(context: "main", key: "--apptype must be followed by one of the following: core gui widget\n");
538#else
539 qWarning() << QCoreApplication::translate("main", "--apptype must be followed by one of the following: core gui\n");
540#endif // QT_WIDGETS_LIB
541 parser.showHelp();
542 }
543 if (parser.isSet(option: verboseOption))
544 verboseMode = true;
545 if (parser.isSet(option: quietOption)) {
546 quietMode = true;
547 verboseMode = false;
548 }
549#if QT_CONFIG(qml_animation)
550 if (parser.isSet(option: slowAnimationsOption))
551 QUnifiedTimer::instance()->setSlowModeEnabled(true);
552 if (parser.isSet(option: fixedAnimationsOption))
553 QUnifiedTimer::instance()->setConsistentTiming(true);
554#endif
555 for (const QString &importPath : parser.values(option: importOption))
556 e.addImportPath(dir: importPath);
557
558 QStringList customSelectors;
559 for (const QString &selector : parser.values(option: selectorOption))
560 customSelectors.append(t: selector);
561 if (!customSelectors.isEmpty()) {
562 QQmlFileSelector *selector = QQmlFileSelector::get(&e);
563 selector->setExtraSelectors(customSelectors);
564 }
565
566#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
567 if (qEnvironmentVariableIsSet(varName: "QSG_CORE_PROFILE") || qEnvironmentVariableIsSet(varName: "QML_CORE_PROFILE")) {
568 QSurfaceFormat surfaceFormat;
569 surfaceFormat.setStencilBufferSize(8);
570 surfaceFormat.setDepthBufferSize(24);
571 surfaceFormat.setVersion(major: 4, minor: 1);
572 surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
573 QSurfaceFormat::setDefaultFormat(surfaceFormat);
574 }
575#endif
576
577 files << parser.values(option: qmlFileOption);
578 if (parser.isSet(option: configOption))
579 confFile = parser.value(option: configOption);
580 if (parser.isSet(option: translationOption))
581 translationFile = parser.value(option: translationOption);
582 if (parser.isSet(option: dummyDataOption))
583 dummyDir = parser.value(option: dummyDataOption);
584 if (parser.isSet(option: rhiOption)) {
585 qputenv(varName: "QSG_RHI", value: "1");
586 const QString rhiBackend = parser.value(option: rhiOption);
587 if (rhiBackend == QLatin1String("default"))
588 qunsetenv(varName: "QSG_RHI_BACKEND");
589 else
590 qputenv(varName: "QSG_RHI_BACKEND", value: rhiBackend.toLatin1());
591 }
592 for (QString posArg : parser.positionalArguments()) {
593 if (posArg == QLatin1String("--"))
594 break;
595 else
596 files << posArg;
597 }
598
599#if QT_CONFIG(translation)
600 // Need to be installed before QQmlApplicationEngine's automatic translation loading
601 // (qt_ translations are loaded there)
602 if (!translationFile.isEmpty()) {
603 QTranslator translator;
604
605 if (translator.load(filename: translationFile)) {
606 app->installTranslator(messageFile: &translator);
607 if (verboseMode)
608 printf(format: "qml: Loaded translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
609 } else {
610 if (!quietMode)
611 printf(format: "qml: Could not load the translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
612 }
613 }
614#else
615 if (!translationFile.isEmpty() && !quietMode)
616 printf("qml: Translation file specified, but Qt built without translation support.\n");
617#endif
618
619 if (quietMode) {
620 qInstallMessageHandler(quietMessageHandler);
621 QLoggingCategory::setFilterRules(QStringLiteral("*=false"));
622 }
623
624 if (files.count() <= 0) {
625#if defined(Q_OS_DARWIN)
626 if (applicationType == QmlApplicationTypeGui)
627 exitTimerId = static_cast<LoaderApplication *>(app.get())->startTimer(FILE_OPEN_EVENT_WAIT_TIME);
628 else
629#endif
630 noFilesGiven();
631 }
632
633 qae = &e;
634 loadConf(override: confFile, quiet: !verboseMode);
635
636 // Load files
637 QScopedPointer<LoadWatcher> lw(new LoadWatcher(&e, files.count()));
638
639 // Load dummy data before loading QML-files
640 if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir())
641 loadDummyDataFiles(engine&: e, directory: dummyDir);
642
643 for (const QString &path : qAsConst(t&: files)) {
644 QUrl url = QUrl::fromUserInput(userInput: path, workingDirectory: QDir::currentPath(), options: QUrl::AssumeLocalFile);
645 if (verboseMode)
646 printf(format: "qml: loading %s\n", qPrintable(url.toString()));
647 QByteArray strippedFile;
648 if (getFileSansBangLine(path, output&: strippedFile))
649 // QQmlComponent won't resolve it for us: it doesn't know it's a valid file if we loadData
650 e.loadData(data: strippedFile, url: e.baseUrl().resolved(relative: url));
651 else // Errors or no bang line
652 e.load(url);
653 }
654
655 if (lw->earlyExit)
656 return lw->returnCode;
657
658 return app->exec();
659}
660
661#include "main.moc"
662

source code of qtdeclarative/tools/qml/main.cpp