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
78 enum 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
89 static QmlApplicationType applicationType =
90 #ifndef QT_GUI_LIB
91 QmlApplicationTypeCore;
92 #else
93 QmlApplicationTypeGui;
94 #endif // QT_GUI_LIB
95
96 static Config *conf = nullptr;
97 static QQmlApplicationEngine *qae = nullptr;
98 #if defined(Q_OS_DARWIN) || defined(QT_GUI_LIB)
99 static int exitTimerId = -1;
100 #endif
101 static const QString iconResourcePath(QStringLiteral(":/qt-project.org/QmlRuntime/resources/qml-64.png"));
102 static const QString confResourcePath(QStringLiteral(":/qt-project.org/QmlRuntime/conf/"));
103 static bool verboseMode = false;
104 static bool quietMode = false;
105
loadConf(const QString & override,bool quiet)106 static 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(QStandardPaths::DataLocation, defaultFileName));
114 if (fi.exists()) {
115 settingsUrl = QUrl::fromLocalFile(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(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(fi.absoluteFilePath());
127 builtIn = true;
128 } else {
129 fi.setFile(override);
130 if (!fi.exists()) {
131 printf("qml: Couldn't find required configuration file: %s\n",
132 qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
133 exit(1);
134 }
135 settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
136 }
137 }
138
139 if (!quiet) {
140 printf("qml: %s\n", QLibraryInfo::build());
141 if (builtIn) {
142 printf("qml: Using built-in configuration: %s\n",
143 qPrintable(override.isEmpty() ? defaultFileName : override));
144 } else {
145 printf("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*>(c2.create());
156
157 if (!conf){
158 printf("qml: Error loading configuration file: %s\n", qPrintable(c2.errorString()));
159 exit(1);
160 }
161 }
162
noFilesGiven()163 void noFilesGiven()
164 {
165 if (!quietMode)
166 printf("qml: No files specified. Terminating.\n");
167 exit(1);
168 }
169
listConfFiles()170 static void listConfFiles()
171 {
172 QDir confResourceDir(confResourcePath);
173 printf("%s\n", qPrintable(QCoreApplication::translate("main", "Built-in configurations:")));
174 for (const QFileInfo &fi : confResourceDir.entryInfoList(QDir::Files))
175 printf(" %s\n", qPrintable(fi.baseName()));
176 exit(0);
177 }
178
179 #ifdef QT_GUI_LIB
180
181 // Loads qml after receiving a QFileOpenEvent
182 class LoaderApplication : public QGuiApplication
183 {
184 public:
LoaderApplication(int & argc,char ** argv)185 LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv)
186 {
187 setWindowIcon(QIcon(iconResourcePath));
188 }
189
event(QEvent * ev)190 bool event(QEvent *ev) override
191 {
192 if (ev->type() == QEvent::FileOpen) {
193 if (exitTimerId >= 0) {
194 killTimer(exitTimerId);
195 exitTimerId = -1;
196 }
197 qae->load(static_cast<QFileOpenEvent *>(ev)->url());
198 }
199 else
200 return QGuiApplication::event(ev);
201 return true;
202 }
203
timerEvent(QTimerEvent *)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
212 class LoadWatcher : public QObject
213 {
214 Q_OBJECT
215 public:
LoadWatcher(QQmlApplicationEngine * e,int expected)216 LoadWatcher(QQmlApplicationEngine *e, int expected)
217 : QObject(e)
218 , expectedFileCount(expected)
219 {
220 connect(e, &QQmlApplicationEngine::objectCreated, this, &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(e, &QQmlEngine::quit, this, &LoadWatcher::quit);
225 connect(e, &QQmlEngine::exit, this, &LoadWatcher::exit);
226 }
227
228 int returnCode = 0;
229 bool earlyExit = false;
230
231 public Q_SLOTS:
checkFinished(QObject * o,const QUrl & url)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(conf->completers))
239 if (o->inherits(ps->itemType().toUtf8().constData()))
240 contain(o, ps->container());
241 }
242 if (haveWindow)
243 return;
244
245 if (! --expectedFileCount) {
246 printf("qml: Did not load any objects, exiting.\n");
247 std::exit(2); // Different return code from qFatal
248 }
249 }
250
quit()251 void quit() {
252 // Will be checked before calling exec()
253 earlyExit = true;
254 returnCode = 0;
255 }
exit(int retCode)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
265 private:
266 void contain(QObject *o, const QUrl &containPath);
267 void checkForWindow(QObject *o);
268
269 private:
270 bool haveWindow = false;
271 int expectedFileCount;
272 };
273
contain(QObject * o,const QUrl & containPath)274 void 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(o2);
281 bool success = false;
282 int idx;
283 if ((idx = o2->metaObject()->indexOfProperty("containedObject")) != -1)
284 success = o2->metaObject()->property(idx).write(o2, QVariant::fromValue<QObject*>(o));
285 if (!success)
286 o->setParent(o2); // Set QObject parent, and assume container will react as needed
287 }
288
checkForWindow(QObject * o)289 void LoadWatcher::checkForWindow(QObject *o)
290 {
291 #if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
292 if (o->isWindowType() && o->inherits("QQuickWindow")) {
293 haveWindow = true;
294 if (verboseMode)
295 connect(o, SIGNAL(openglContextCreated(QOpenGLContext*)),
296 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)
onOpenGlContextCreated(QOpenGLContext * context)304 void LoadWatcher::onOpenGlContextCreated(QOpenGLContext *context)
305 {
306 context->makeCurrent(qobject_cast<QWindow *>(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(output.constData());
317 context->doneCurrent();
318 }
319 #endif // QT_GUI_LIB && !QT_NO_OPENGL
320
quietMessageHandler(QtMsgType type,const QMessageLogContext & ctxt,const QString & msg)321 void 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(-1);
329 case QtCriticalMsg:
330 case QtDebugMsg:
331 case QtInfoMsg:
332 case QtWarningMsg:
333 ;
334 }
335 }
336
337 // Called before application initialization
getAppFlags(int argc,char ** argv)338 static void getAppFlags(int argc, char **argv)
339 {
340 #ifdef QT_GUI_LIB
341 for (int i=0; i<argc; i++) {
342 if (!strcmp(argv[i], "--apptype") || !strcmp(argv[i], "-a") || !strcmp(argv[i], "-apptype")) {
343 applicationType = QmlApplicationTypeUnknown;
344 if (i+1 < argc) {
345 ++i;
346 if (!strcmp(argv[i], "core"))
347 applicationType = QmlApplicationTypeCore;
348 else if (!strcmp(argv[i], "gui"))
349 applicationType = QmlApplicationTypeGui;
350 # ifdef QT_WIDGETS_LIB
351 else if (!strcmp(argv[i], "widget"))
352 applicationType = QmlApplicationTypeWidget;
353 # endif // QT_WIDGETS_LIB
354
355 }
356 } else if (!strcmp(argv[i], "-desktop") || !strcmp(argv[i], "--desktop")) {
357 QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
358 } else if (!strcmp(argv[i], "-gles") || !strcmp(argv[i], "--gles")) {
359 QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
360 } else if (!strcmp(argv[i], "-software") || !strcmp(argv[i], "--software")) {
361 QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
362 } else if (!strcmp(argv[i], "-scaling") || !strcmp(argv[i], "--scaling")) {
363 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
364 } else if (!strcmp(argv[i], "-no-scaling") || !strcmp(argv[i], "--no-scaling")) {
365 QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
366 }
367 }
368 #else
369 Q_UNUSED(argc)
370 Q_UNUSED(argv)
371 #endif // QT_GUI_LIB
372 }
373
getFileSansBangLine(const QString & path,QByteArray & output)374 bool getFileSansBangLine(const QString &path, QByteArray &output)
375 {
376 QFile f(path);
377 if (!f.open(QFile::ReadOnly | QFile::Text))
378 return false;
379 output = f.readAll();
380 if (output.startsWith("#!")) {//Remove first line in this case (except \n, to avoid disturbing line count)
381 output.remove(0, output.indexOf('\n'));
382 return true;
383 }
384 return false;
385 }
386
loadDummyDataFiles(QQmlEngine & engine,const QString & directory)387 static 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(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("qml: Loaded dummy data: %s\n", qPrintable(dir.filePath(qml)));
404 qml.truncate(qml.length()-4);
405 engine.rootContext()->setContextProperty(qml, dummyData);
406 dummyData->setParent(&engine);
407 }
408 }
409 }
410
main(int argc,char * argv[])411 int 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>(argc, argv);
419 break;
420 #ifdef QT_WIDGETS_LIB
421 case QmlApplicationTypeWidget:
422 app = qt_make_unique<QApplication>(argc, 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>(argc, 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("main", "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(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("main", "Prepend the given path to the import paths."), QStringLiteral("path"));
463 parser.addOption(importOption);
464 QCommandLineOption qmlFileOption(QStringLiteral("f"),
465 QCoreApplication::translate("main", "Load the given file as a QML file."), QStringLiteral("file"));
466 parser.addOption(qmlFileOption);
467 QCommandLineOption configOption(QStringList() << QStringLiteral("c") << QStringLiteral("config"),
468 QCoreApplication::translate("main", "Load the given built-in configuration or configuration file."), QStringLiteral("file"));
469 parser.addOption(configOption);
470 QCommandLineOption listConfOption(QStringList() << QStringLiteral("list-conf"),
471 QCoreApplication::translate("main", "List the built-in configurations."));
472 parser.addOption(listConfOption);
473 QCommandLineOption translationOption(QStringLiteral("translation"),
474 QCoreApplication::translate("main", "Load the given file as the translations file."), QStringLiteral("file"));
475 parser.addOption(translationOption);
476 QCommandLineOption dummyDataOption(QStringLiteral("dummy-data"),
477 QCoreApplication::translate("main", "Load QML files from the given directory as context properties."), QStringLiteral("file"));
478 parser.addOption(dummyDataOption);
479 #ifdef QT_GUI_LIB
480 // OpenGL options
481 QCommandLineOption glDesktopOption(QStringLiteral("desktop"),
482 QCoreApplication::translate("main", "Force use of desktop OpenGL (AA_UseDesktopOpenGL)."));
483 parser.addOption(glDesktopOption); // Just for the help text... we've already handled this argument above
484 QCommandLineOption glEsOption(QStringLiteral("gles"),
485 QCoreApplication::translate("main", "Force use of GLES (AA_UseOpenGLES)."));
486 parser.addOption(glEsOption); // Just for the help text... we've already handled this argument above
487 QCommandLineOption glSoftwareOption(QStringLiteral("software"),
488 QCoreApplication::translate("main", "Force use of software rendering (AA_UseSoftwareOpenGL)."));
489 parser.addOption(glSoftwareOption); // Just for the help text... we've already handled this argument above
490 QCommandLineOption scalingOption(QStringLiteral("scaling"),
491 QCoreApplication::translate("main", "Enable High DPI scaling (AA_EnableHighDpiScaling)."));
492 parser.addOption(scalingOption); // Just for the help text... we've already handled this argument above
493 QCommandLineOption noScalingOption(QStringLiteral("no-scaling"),
494 QCoreApplication::translate("main", "Disable High DPI scaling (AA_DisableHighDpiScaling)."));
495 parser.addOption(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("main", "Suppress all output."));
500 parser.addOption(quietOption);
501 QCommandLineOption verboseOption(QStringLiteral("verbose"),
502 QCoreApplication::translate("main", "Print information about what qml is doing, like specific file URLs being loaded."));
503 parser.addOption(verboseOption);
504 QCommandLineOption slowAnimationsOption(QStringLiteral("slow-animations"),
505 QCoreApplication::translate("main", "Run all animations in slow motion."));
506 parser.addOption(slowAnimationsOption);
507 QCommandLineOption fixedAnimationsOption(QStringLiteral("fixed-animations"),
508 QCoreApplication::translate("main", "Run animations off animation tick rather than wall time."));
509 parser.addOption(fixedAnimationsOption);
510 QCommandLineOption rhiOption(QStringList() << QStringLiteral("r") << QStringLiteral("rhi"),
511 QCoreApplication::translate("main", "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(rhiOption);
515 QCommandLineOption selectorOption(QStringLiteral("S"), QCoreApplication::translate("main",
516 "Add selector to the list of QQmlFileSelectors."), QStringLiteral("selector"));
517 parser.addOption(selectorOption);
518
519 // Positional arguments
520 parser.addPositionalArgument("files",
521 QCoreApplication::translate("main", "Any number of QML files can be loaded. They will share the same engine."), "[files...]");
522 parser.addPositionalArgument("args",
523 QCoreApplication::translate("main", "Arguments after '--' are ignored, but passed through to the application.arguments variable in QML."), "[-- args...]");
524
525 if (!parser.parse(QCoreApplication::arguments())) {
526 qWarning() << parser.errorText();
527 exit(1);
528 }
529 if (parser.isSet(versionOption))
530 parser.showVersion();
531 if (parser.isSet(helpOption))
532 parser.showHelp();
533 if (parser.isSet(listConfOption))
534 listConfFiles();
535 if (applicationType == QmlApplicationTypeUnknown) {
536 #ifdef QT_WIDGETS_LIB
537 qWarning() << QCoreApplication::translate("main", "--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(verboseOption))
544 verboseMode = true;
545 if (parser.isSet(quietOption)) {
546 quietMode = true;
547 verboseMode = false;
548 }
549 #if QT_CONFIG(qml_animation)
550 if (parser.isSet(slowAnimationsOption))
551 QUnifiedTimer::instance()->setSlowModeEnabled(true);
552 if (parser.isSet(fixedAnimationsOption))
553 QUnifiedTimer::instance()->setConsistentTiming(true);
554 #endif
555 for (const QString &importPath : parser.values(importOption))
556 e.addImportPath(importPath);
557
558 QStringList customSelectors;
559 for (const QString &selector : parser.values(selectorOption))
560 customSelectors.append(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("QSG_CORE_PROFILE") || qEnvironmentVariableIsSet("QML_CORE_PROFILE")) {
568 QSurfaceFormat surfaceFormat;
569 surfaceFormat.setStencilBufferSize(8);
570 surfaceFormat.setDepthBufferSize(24);
571 surfaceFormat.setVersion(4, 1);
572 surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
573 QSurfaceFormat::setDefaultFormat(surfaceFormat);
574 }
575 #endif
576
577 files << parser.values(qmlFileOption);
578 if (parser.isSet(configOption))
579 confFile = parser.value(configOption);
580 if (parser.isSet(translationOption))
581 translationFile = parser.value(translationOption);
582 if (parser.isSet(dummyDataOption))
583 dummyDir = parser.value(dummyDataOption);
584 if (parser.isSet(rhiOption)) {
585 qputenv("QSG_RHI", "1");
586 const QString rhiBackend = parser.value(rhiOption);
587 if (rhiBackend == QLatin1String("default"))
588 qunsetenv("QSG_RHI_BACKEND");
589 else
590 qputenv("QSG_RHI_BACKEND", 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(translationFile)) {
606 app->installTranslator(&translator);
607 if (verboseMode)
608 printf("qml: Loaded translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
609 } else {
610 if (!quietMode)
611 printf("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(confFile, !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(e, dummyDir);
642
643 for (const QString &path : qAsConst(files)) {
644 QUrl url = QUrl::fromUserInput(path, QDir::currentPath(), QUrl::AssumeLocalFile);
645 if (verboseMode)
646 printf("qml: loading %s\n", qPrintable(url.toString()));
647 QByteArray strippedFile;
648 if (getFileSansBangLine(path, strippedFile))
649 // QQmlComponent won't resolve it for us: it doesn't know it's a valid file if we loadData
650 e.loadData(strippedFile, e.baseUrl().resolved(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