1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtCore/qabstractanimation.h>
30#include <QtCore/qdir.h>
31#include <QtCore/qmath.h>
32#include <QtCore/qelapsedtimer.h>
33#include <QtCore/qpointer.h>
34#include <QtCore/qscopedpointer.h>
35#include <QtCore/qtextstream.h>
36#include <QtCore/qregularexpression.h>
37
38#include <QtGui/QGuiApplication>
39#include <QtGui/QOpenGLFunctions>
40
41#include <QtQml/qqml.h>
42#include <QtQml/qqmlengine.h>
43#include <QtQml/qqmlcomponent.h>
44#include <QtQml/qqmlcontext.h>
45#include <QtQml/qqmlfileselector.h>
46
47#include <QtQuick/qquickitem.h>
48#include <QtQuick/qquickview.h>
49
50#include <private/qabstractanimation_p.h>
51#include <private/qopenglcontext_p.h>
52
53#ifdef QT_WIDGETS_LIB
54#include <QtWidgets/QApplication>
55#if QT_CONFIG(filedialog)
56#include <QtWidgets/QFileDialog>
57#endif // QT_CONFIG(filedialog)
58#endif // QT_WIDGETS_LIB
59
60#include <QtCore/QTranslator>
61#include <QtCore/QLibraryInfo>
62
63#ifdef QML_RUNTIME_TESTING
64class RenderStatistics
65{
66public:
67 static void updateStats();
68 static void printTotalStats();
69private:
70 static QVector<qreal> timePerFrame;
71 static QVector<int> timesPerFrames;
72};
73
74QVector<qreal> RenderStatistics::timePerFrame;
75QVector<int> RenderStatistics::timesPerFrames;
76
77void RenderStatistics::updateStats()
78{
79 static QElapsedTimer time;
80 static int frames;
81 static int lastTime;
82
83 if (frames == 0) {
84 time.start();
85 } else {
86 int elapsed = time.elapsed();
87 timesPerFrames.append(t: elapsed - lastTime);
88 lastTime = elapsed;
89
90 if (elapsed > 5000) {
91 qreal avgtime = elapsed / (qreal) frames;
92 qreal var = 0;
93 for (int i = 0; i < timesPerFrames.size(); ++i) {
94 qreal diff = timesPerFrames.at(i) - avgtime;
95 var += diff * diff;
96 }
97 var /= timesPerFrames.size();
98
99 printf(format: "Average time per frame: %f ms (%i fps), std.dev: %f ms\n", avgtime, qRound(d: 1000. / avgtime), qSqrt(v: var));
100
101 timePerFrame.append(t: avgtime);
102 timesPerFrames.clear();
103 time.start();
104 lastTime = 0;
105 frames = 0;
106 }
107 }
108 ++frames;
109}
110
111void RenderStatistics::printTotalStats()
112{
113 int count = timePerFrame.count();
114 if (count == 0)
115 return;
116
117 qreal minTime = 0;
118 qreal maxTime = 0;
119 qreal avg = 0;
120 for (int i = 0; i < count; ++i) {
121 minTime = minTime == 0 ? timePerFrame.at(i) : qMin(a: minTime, b: timePerFrame.at(i));
122 maxTime = qMax(a: maxTime, b: timePerFrame.at(i));
123 avg += timePerFrame.at(i);
124 }
125 avg /= count;
126
127 puts(s: " ");
128 puts(s: "----- Statistics -----");
129 printf(format: "Average time per frame: %f ms (%i fps)\n", avg, qRound(d: 1000. / avg));
130 printf(format: "Best time per frame: %f ms (%i fps)\n", minTime, int(1000 / minTime));
131 printf(format: "Worst time per frame: %f ms (%i fps)\n", maxTime, int(1000 / maxTime));
132 puts(s: "----------------------");
133 puts(s: " ");
134}
135#endif
136
137struct Options
138{
139 enum QmlApplicationType
140 {
141 QmlApplicationTypeGui,
142 QmlApplicationTypeWidget,
143#ifdef QT_WIDGETS_LIB
144 DefaultQmlApplicationType = QmlApplicationTypeWidget
145#else
146 DefaultQmlApplicationType = QmlApplicationTypeGui
147#endif
148 };
149
150 Options()
151 : textRenderType(QQuickWindow::textRenderType())
152 {
153 // QtWebEngine needs a shared context in order for the GPU thread to
154 // upload textures.
155 applicationAttributes.append(t: Qt::AA_ShareOpenGLContexts);
156 }
157
158 QUrl url;
159 bool originalQml = false;
160 bool originalQmlRaster = false;
161 bool maximized = false;
162 bool fullscreen = false;
163 bool transparent = false;
164 bool clip = false;
165 bool versionDetection = true;
166 bool slowAnimations = false;
167 bool quitImmediately = false;
168 bool resizeViewToRootItem = false;
169 bool multisample = false;
170 bool coreProfile = false;
171 bool verbose = false;
172 bool rhi = false;
173 bool rhiBackendSet = false;
174 QVector<Qt::ApplicationAttribute> applicationAttributes;
175 QString translationFile;
176 QmlApplicationType applicationType = DefaultQmlApplicationType;
177 QQuickWindow::TextRenderType textRenderType;
178 QString rhiBackend;
179};
180
181#if defined(QMLSCENE_BUNDLE)
182QFileInfoList findQmlFiles(const QString &dirName)
183{
184 QDir dir(dirName);
185
186 QFileInfoList ret;
187 if (dir.exists()) {
188 const QFileInfoList fileInfos = dir.entryInfoList(QStringList() << "*.qml",
189 QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
190
191 for (const QFileInfo &fileInfo : fileInfos) {
192 if (fileInfo.isDir())
193 ret += findQmlFiles(fileInfo.filePath());
194 else if (fileInfo.fileName().length() > 0 && fileInfo.fileName().at(0).isLower())
195 ret.append(fileInfo);
196 }
197 }
198
199 return ret;
200}
201
202static int displayOptionsDialog(Options *options)
203{
204 QDialog dialog;
205
206 QFormLayout *layout = new QFormLayout(&dialog);
207
208 QComboBox *qmlFileComboBox = new QComboBox(&dialog);
209 const QFileInfoList fileInfos = findQmlFiles(":/bundle") + findQmlFiles("./qmlscene-resources");
210
211 for (const QFileInfo &fileInfo : fileInfos)
212 qmlFileComboBox->addItem(fileInfo.dir().dirName() + QLatin1Char('/') + fileInfo.fileName(), QVariant::fromValue(fileInfo));
213
214 QCheckBox *originalCheckBox = new QCheckBox(&dialog);
215 originalCheckBox->setText("Use original QML viewer");
216 originalCheckBox->setChecked(options->originalQml);
217
218 QCheckBox *fullscreenCheckBox = new QCheckBox(&dialog);
219 fullscreenCheckBox->setText("Start fullscreen");
220 fullscreenCheckBox->setChecked(options->fullscreen);
221
222 QCheckBox *maximizedCheckBox = new QCheckBox(&dialog);
223 maximizedCheckBox->setText("Start maximized");
224 maximizedCheckBox->setChecked(options->maximized);
225
226 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
227 Qt::Horizontal,
228 &dialog);
229 QObject::connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
230 QObject::connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
231
232 layout->addRow("Qml file:", qmlFileComboBox);
233 layout->addWidget(originalCheckBox);
234 layout->addWidget(maximizedCheckBox);
235 layout->addWidget(fullscreenCheckBox);
236 layout->addWidget(buttonBox);
237
238 int result = dialog.exec();
239 if (result == QDialog::Accepted) {
240 QVariant variant = qmlFileComboBox->itemData(qmlFileComboBox->currentIndex());
241 QFileInfo fileInfo = variant.value<QFileInfo>();
242
243 if (fileInfo.canonicalFilePath().startsWith(QLatin1Char(':')))
244 options->file = QUrl("qrc" + fileInfo.canonicalFilePath());
245 else
246 options->file = QUrl::fromLocalFile(fileInfo.canonicalFilePath());
247 options->originalQml = originalCheckBox->isChecked();
248 options->maximized = maximizedCheckBox->isChecked();
249 options->fullscreen = fullscreenCheckBox->isChecked();
250 }
251 return result;
252}
253#endif
254
255static bool checkVersion(const QUrl &url)
256{
257 if (!qgetenv(varName: "QMLSCENE_IMPORT_NAME").isEmpty())
258 fprintf(stderr, format: "QMLSCENE_IMPORT_NAME is no longer supported.\n");
259
260 if (!url.isLocalFile())
261 return true;
262
263 const QString fileName = url.toLocalFile();
264 QFile f(fileName);
265 if (!f.open(flags: QFile::ReadOnly | QFile::Text)) {
266 fprintf(stderr, format: "qmlscene: failed to check version of file '%s', could not open...\n",
267 qPrintable(fileName));
268 return false;
269 }
270
271 QRegularExpression quick1("^\\s*import +QtQuick +1\\.\\w*");
272 QRegularExpression qt47("^\\s*import +Qt +4\\.7");
273
274 QTextStream stream(&f);
275 bool codeFound= false;
276 while (!codeFound) {
277 if (stream.atEnd()) {
278 fprintf(stderr, format: "qmlscene: no code found in file '%s'.\n", qPrintable(fileName));
279 return false;
280 }
281 QString line = stream.readLine();
282 if (line.contains(c: QLatin1Char('{'))) {
283 codeFound = true;
284 } else {
285 QString import;
286 QRegularExpressionMatch match = quick1.match(subject: line);
287 if (match.hasMatch())
288 import = match.captured(nth: 0).trimmed();
289 else if ((match = qt47.match(subject: line)).hasMatch())
290 import = match.captured(nth: 0).trimmed();
291
292 if (!import.isNull()) {
293 fprintf(stderr, format: "qmlscene: '%s' is no longer supported.\n"
294 "Use qmlviewer to load file '%s'.\n",
295 qPrintable(import),
296 qPrintable(fileName));
297 return false;
298 }
299 }
300 }
301
302 return true;
303}
304
305static void displayFileDialog(Options *options)
306{
307#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
308 if (options->applicationType == Options::QmlApplicationTypeWidget) {
309 QString fileName = QFileDialog::getOpenFileName(parent: nullptr, caption: "Open QML file", dir: QString(), filter: "QML Files (*.qml)");
310 if (!fileName.isEmpty()) {
311 QFileInfo fi(fileName);
312 options->url = QUrl::fromLocalFile(localfile: fi.canonicalFilePath());
313 }
314 return;
315 }
316#endif // QT_WIDGETS_LIB && QT_CONFIG(filedialog)
317 Q_UNUSED(options);
318 puts(s: "No filename specified...");
319}
320
321static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
322{
323 QDir dir(directory+"/dummydata", "*.qml");
324 QStringList list = dir.entryList();
325 for (int i = 0; i < list.size(); ++i) {
326 QString qml = list.at(i);
327 QQmlComponent comp(&engine, dir.filePath(fileName: qml));
328 QObject *dummyData = comp.create();
329
330 if(comp.isError()) {
331 const QList<QQmlError> errors = comp.errors();
332 for (const QQmlError &error : errors)
333 fprintf(stderr, format: "%s\n", qPrintable(error.toString()));
334 }
335
336 if (dummyData) {
337 fprintf(stderr, format: "Loaded dummy data: %s\n", qPrintable(dir.filePath(qml)));
338 qml.truncate(pos: qml.length()-4);
339 engine.rootContext()->setContextProperty(qml, dummyData);
340 dummyData->setParent(&engine);
341 }
342 }
343}
344
345static void usage()
346{
347 puts(s: "Usage: qmlscene [options] <filename>");
348 puts(s: " ");
349 puts(s: " Options:");
350 puts(s: " --maximized ...................... Run maximized");
351 puts(s: " --fullscreen ..................... Run fullscreen");
352 puts(s: " --transparent .................... Make the window transparent");
353 puts(s: " --multisample .................... Enable multisampling (OpenGL anti-aliasing)");
354 puts(s: " --core-profile ................... Request a core profile OpenGL context");
355 puts(s: " --rhi [vulkan|metal|d3d11|gl] .... Use the Qt graphics abstraction (RHI) instead of OpenGL directly.\n"
356 " .... Backend has platform specific defaults. Specify to override.");
357 puts(s: " --no-version-detection ........... Do not try to detect the version of the .qml file");
358 puts(s: " --slow-animations ................ Run all animations in slow motion");
359 puts(s: " --resize-to-root ................. Resize the window to the size of the root item");
360 puts(s: " --quit ........................... Quit immediately after starting");
361 puts(s: " --disable-context-sharing ........ Disable the use of a shared GL context for QtQuick Windows\n"
362 " ........ (remove AA_ShareOpenGLContexts)");
363 puts(s: " --desktop......................... Force use of desktop GL (AA_UseDesktopOpenGL)");
364 puts(s: " --gles............................ Force use of GLES (AA_UseOpenGLES)");
365 puts(s: " --software........................ Force use of software rendering (AA_UseOpenGLES)");
366 puts(s: " --scaling......................... Enable High DPI scaling (AA_EnableHighDpiScaling)");
367 puts(s: " --no-scaling...................... Disable High DPI scaling (AA_DisableHighDpiScaling)");
368 puts(s: " --verbose......................... Print version and graphical diagnostics for the run-time");
369#ifdef QT_WIDGETS_LIB
370 puts(s: " --apptype [gui|widgets] .......... Select which application class to use. Default is widgets.");
371#endif
372 puts(s: " --textrendertype [qt|native]...... Select the default render type for text-like elements.");
373 puts(s: " -I <path> ........................ Add <path> to the list of import paths");
374 puts(s: " -S <selector> .................... Add <selector> to the list of QQmlFileSelector selectors");
375 puts(s: " -P <path> ........................ Add <path> to the list of plugin paths");
376 puts(s: " -translation <translationfile> ... Set the language to run in");
377
378 puts(s: " ");
379 exit(status: 1);
380}
381#if QT_CONFIG(opengl)
382// Listen on GL context creation of the QQuickWindow in order to print diagnostic output.
383class DiagnosticGlContextCreationListener : public QObject {
384 Q_OBJECT
385public:
386 explicit DiagnosticGlContextCreationListener(QQuickWindow *window) : QObject(window)
387 {
388 connect(sender: window, signal: &QQuickWindow::openglContextCreated,
389 receiver: this, slot: &DiagnosticGlContextCreationListener::onOpenGlContextCreated);
390 }
391
392private slots:
393 void onOpenGlContextCreated(QOpenGLContext *context)
394 {
395 context->makeCurrent(surface: qobject_cast<QQuickWindow *>(object: parent()));
396 QOpenGLFunctions functions(context);
397 QByteArray output = "Vendor : ";
398 output += reinterpret_cast<const char *>(functions.glGetString(GL_VENDOR));
399 output += "\nRenderer: ";
400 output += reinterpret_cast<const char *>(functions.glGetString(GL_RENDERER));
401 output += "\nVersion : ";
402 output += reinterpret_cast<const char *>(functions.glGetString(GL_VERSION));
403 output += "\nLanguage: ";
404 output += reinterpret_cast<const char *>(functions.glGetString(GL_SHADING_LANGUAGE_VERSION));
405 puts(s: output.constData());
406 context->doneCurrent();
407 deleteLater();
408 }
409
410};
411#endif
412
413static void setWindowTitle(bool verbose, const QObject *topLevel, QWindow *window)
414{
415 const QString oldTitle = window->title();
416 QString newTitle = oldTitle;
417 if (newTitle.isEmpty()) {
418 newTitle = QLatin1String("qmlscene");
419 if (!qobject_cast<const QWindow *>(o: topLevel) && !topLevel->objectName().isEmpty())
420 newTitle += QLatin1String(": ") + topLevel->objectName();
421 }
422 if (verbose) {
423 newTitle += QLatin1String(" [Qt ") + QLatin1String(QT_VERSION_STR) + QLatin1Char(' ')
424 + QGuiApplication::platformName() + QLatin1Char(' ');
425#if QT_CONFIG(opengl)
426 newTitle += QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
427 ? QLatin1String("GL") : QLatin1String("GLES");
428#endif
429 newTitle += QLatin1Char(']');
430 }
431 if (oldTitle != newTitle)
432 window->setTitle(newTitle);
433}
434
435static QUrl parseUrlArgument(const QString &arg)
436{
437 const QUrl url = QUrl::fromUserInput(userInput: arg, workingDirectory: QDir::currentPath(), options: QUrl::AssumeLocalFile);
438 if (!url.isValid()) {
439 fprintf(stderr, format: "Invalid URL: \"%s\"\n", qPrintable(arg));
440 return QUrl();
441 }
442 if (url.isLocalFile()) {
443 const QFileInfo fi(url.toLocalFile());
444 if (!fi.exists()) {
445 fprintf(stderr, format: "\"%s\" does not exist.\n",
446 qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
447 return QUrl();
448 }
449 }
450 return url;
451}
452
453static QQuickWindow::TextRenderType parseTextRenderType(const QString &renderType)
454{
455 if (renderType == QLatin1String("qt"))
456 return QQuickWindow::QtTextRendering;
457 else if (renderType == QLatin1String("native"))
458 return QQuickWindow::NativeTextRendering;
459
460 usage();
461
462 Q_UNREACHABLE();
463 return QQuickWindow::QtTextRendering;
464}
465
466int main(int argc, char ** argv)
467{
468 Options options;
469
470 QStringList imports;
471 QStringList customSelectors;
472 QStringList pluginPaths;
473
474 // Parse arguments for application attributes to be applied before Q[Gui]Application creation.
475 for (int i = 1; i < argc; ++i) {
476 const char *arg = argv[i];
477 if (!qstrcmp(str1: arg, str2: "--disable-context-sharing")) {
478 options.applicationAttributes.removeAll(t: Qt::AA_ShareOpenGLContexts);
479 } else if (!qstrcmp(str1: arg, str2: "--gles")) {
480 options.applicationAttributes.append(t: Qt::AA_UseOpenGLES);
481 } else if (!qstrcmp(str1: arg, str2: "--software")) {
482 options.applicationAttributes.append(t: Qt::AA_UseSoftwareOpenGL);
483 } else if (!qstrcmp(str1: arg, str2: "--desktop")) {
484 options.applicationAttributes.append(t: Qt::AA_UseDesktopOpenGL);
485 } else if (!qstrcmp(str1: arg, str2: "--scaling")) {
486 options.applicationAttributes.append(t: Qt::AA_EnableHighDpiScaling);
487 } else if (!qstrcmp(str1: arg, str2: "--no-scaling")) {
488 options.applicationAttributes.append(t: Qt::AA_DisableHighDpiScaling);
489 } else if (!qstrcmp(str1: arg, str2: "--transparent")) {
490 options.transparent = true;
491 } else if (!qstrcmp(str1: arg, str2: "--multisample")) {
492 options.multisample = true;
493 } else if (!qstrcmp(str1: arg, str2: "--core-profile")) {
494 options.coreProfile = true;
495 } else if (!qstrcmp(str1: arg, str2: "--apptype")) {
496 if (++i >= argc)
497 usage();
498 if (!qstrcmp(str1: argv[i], str2: "gui"))
499 options.applicationType = Options::QmlApplicationTypeGui;
500 }
501 }
502
503 if (qEnvironmentVariableIsSet(varName: "QMLSCENE_CORE_PROFILE")
504 || qEnvironmentVariableIsSet(varName: "QSG_CORE_PROFILE"))
505 options.coreProfile = true;
506
507 // Set default surface format before creating the window
508 QSurfaceFormat surfaceFormat;
509 surfaceFormat.setStencilBufferSize(8);
510 surfaceFormat.setDepthBufferSize(24);
511 if (options.multisample)
512 surfaceFormat.setSamples(16);
513 if (options.transparent)
514 surfaceFormat.setAlphaBufferSize(8);
515 if (options.coreProfile) {
516 surfaceFormat.setVersion(major: 4, minor: 1);
517 surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
518 }
519 QSurfaceFormat::setDefaultFormat(surfaceFormat);
520
521 for (Qt::ApplicationAttribute a : qAsConst(t&: options.applicationAttributes))
522 QCoreApplication::setAttribute(attribute: a);
523 QScopedPointer<QGuiApplication> app;
524#ifdef QT_WIDGETS_LIB
525 if (options.applicationType == Options::QmlApplicationTypeWidget)
526 app.reset(other: new QApplication(argc, argv));
527#endif
528 if (app.isNull())
529 app.reset(other: new QGuiApplication(argc, argv));
530 QCoreApplication::setApplicationName(QStringLiteral("QtQmlViewer"));
531 QCoreApplication::setOrganizationName(QStringLiteral("QtProject"));
532 QCoreApplication::setOrganizationDomain(QStringLiteral("qt-project.org"));
533 QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
534
535 const QStringList arguments = QCoreApplication::arguments();
536 for (int i = 1, size = arguments.size(); i < size; ++i) {
537 if (!arguments.at(i).startsWith(c: QLatin1Char('-'))) {
538 options.url = parseUrlArgument(arg: arguments.at(i));
539 } else {
540 const QString lowerArgument = arguments.at(i).toLower();
541 if (lowerArgument == QLatin1String("--maximized"))
542 options.maximized = true;
543 else if (lowerArgument == QLatin1String("--fullscreen"))
544 options.fullscreen = true;
545 else if (lowerArgument == QLatin1String("--clip"))
546 options.clip = true;
547 else if (lowerArgument == QLatin1String("--no-version-detection"))
548 options.versionDetection = false;
549 else if (lowerArgument == QLatin1String("--slow-animations"))
550 options.slowAnimations = true;
551 else if (lowerArgument == QLatin1String("--quit"))
552 options.quitImmediately = true;
553 else if (lowerArgument == QLatin1String("-translation"))
554 options.translationFile = QLatin1String(argv[++i]);
555 else if (lowerArgument == QLatin1String("--resize-to-root"))
556 options.resizeViewToRootItem = true;
557 else if (lowerArgument == QLatin1String("--verbose"))
558 options.verbose = true;
559 else if (lowerArgument == QLatin1String("--rhi")) {
560 options.rhi = true;
561 if (i + 1 < size && !arguments.at(i: i + 1).startsWith(c: QLatin1Char('-'))) {
562 options.rhiBackendSet = true;
563 options.rhiBackend = arguments.at(i: ++i);
564 }
565 } else if (lowerArgument == QLatin1String("-i") && i + 1 < size)
566 imports.append(t: arguments.at(i: ++i));
567 else if (lowerArgument == QLatin1String("-s") && i + 1 < size)
568 customSelectors.append(t: arguments.at(i: ++i));
569 else if (lowerArgument == QLatin1String("-p") && i + 1 < size)
570 pluginPaths.append(t: arguments.at(i: ++i));
571 else if (lowerArgument == QLatin1String("--apptype"))
572 ++i; // Consume previously parsed argument
573 else if (lowerArgument == QLatin1String("--textrendertype") && i + 1 < size)
574 options.textRenderType = parseTextRenderType(renderType: arguments.at(i: ++i));
575 else if (lowerArgument == QLatin1String("--help")
576 || lowerArgument == QLatin1String("-help")
577 || lowerArgument == QLatin1String("--h")
578 || lowerArgument == QLatin1String("-h"))
579 usage();
580 }
581 }
582
583#if QT_CONFIG(translation)
584 QLocale locale;
585 QTranslator qtTranslator;
586 if (qtTranslator.load(locale, filename: QLatin1String("qt"), prefix: QLatin1String("_"), directory: QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
587 QCoreApplication::installTranslator(messageFile: &qtTranslator);
588 QTranslator translator;
589 if (translator.load(locale, filename: QLatin1String("qmlscene"), prefix: QLatin1String("_"), directory: QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
590 QCoreApplication::installTranslator(messageFile: &translator);
591
592 QTranslator qmlTranslator;
593 if (!options.translationFile.isEmpty()) {
594 if (qmlTranslator.load(filename: options.translationFile)) {
595 QCoreApplication::installTranslator(messageFile: &qmlTranslator);
596 } else {
597 fprintf(stderr, format: "Could not load the translation file \"%s\"\n",
598 qPrintable(options.translationFile));
599 }
600 }
601#endif
602
603 QQuickWindow::setTextRenderType(options.textRenderType);
604
605 QUnifiedTimer::instance()->setSlowModeEnabled(options.slowAnimations);
606
607 if (options.rhi) {
608 qputenv(varName: "QSG_RHI", value: "1");
609 if (options.rhiBackendSet)
610 qputenv(varName: "QSG_RHI_BACKEND", value: options.rhiBackend.toLatin1());
611 else
612 qunsetenv(varName: "QSG_RHI_BACKEND");
613 }
614
615 if (options.url.isEmpty())
616#if defined(QMLSCENE_BUNDLE)
617 displayOptionsDialog(&options);
618#else
619 displayFileDialog(options: &options);
620#endif
621
622 int exitCode = 0;
623
624 if (options.verbose)
625 puts(s: QLibraryInfo::build());
626
627 if (!options.url.isEmpty()) {
628 if (!options.versionDetection || checkVersion(url: options.url)) {
629 // TODO: as soon as the engine construction completes, the debug service is
630 // listening for connections. But actually we aren't ready to debug anything.
631 QQmlEngine engine;
632 QQmlFileSelector* selector = new QQmlFileSelector(&engine, &engine);
633 selector->setExtraSelectors(customSelectors);
634 QPointer<QQmlComponent> component = new QQmlComponent(&engine);
635 for (int i = 0; i < imports.size(); ++i)
636 engine.addImportPath(dir: imports.at(i));
637 for (int i = 0; i < pluginPaths.size(); ++i)
638 engine.addPluginPath(dir: pluginPaths.at(i));
639 if (options.url.isLocalFile()) {
640 QFileInfo fi(options.url.toLocalFile());
641#if QT_CONFIG(translation)
642 QTranslator *translator = new QTranslator(app.get());
643 if (translator->load(locale: QLocale(), filename: QLatin1String("qml"), prefix: QLatin1String("_"), directory: fi.path() + QLatin1String("/i18n")))
644 QCoreApplication::installTranslator(messageFile: translator);
645#endif
646 loadDummyDataFiles(engine, directory: fi.path());
647 }
648 QObject::connect(sender: &engine, SIGNAL(quit()), receiver: QCoreApplication::instance(), SLOT(quit()));
649 QObject::connect(sender: &engine, signal: &QQmlEngine::exit, context: QCoreApplication::instance(), slot: &QCoreApplication::exit);
650 component->loadUrl(url: options.url);
651 while (component->isLoading())
652 QCoreApplication::processEvents();
653 if ( !component->isReady() ) {
654 fprintf(stderr, format: "%s\n", qPrintable(component->errorString()));
655 return -1;
656 }
657
658 QObject *topLevel = component->create();
659 if (!topLevel && component->isError()) {
660 fprintf(stderr, format: "%s\n", qPrintable(component->errorString()));
661 return -1;
662 }
663
664 QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(object: topLevel));
665 if (window) {
666 engine.setIncubationController(window->incubationController());
667 } else {
668 QQuickItem *contentItem = qobject_cast<QQuickItem *>(object: topLevel);
669 if (contentItem) {
670 QQuickView* qxView = new QQuickView(&engine, nullptr);
671 window.reset(other: qxView);
672 // Set window default properties; the qml can still override them
673 if (options.resizeViewToRootItem)
674 qxView->setResizeMode(QQuickView::SizeViewToRootObject);
675 else
676 qxView->setResizeMode(QQuickView::SizeRootObjectToView);
677 qxView->setContent(url: options.url, component, item: contentItem);
678 }
679 }
680
681 if (window) {
682 setWindowTitle(verbose: options.verbose, topLevel, window: window.data());
683#if QT_CONFIG(opengl)
684 if (options.verbose)
685 new DiagnosticGlContextCreationListener(window.data());
686#endif
687 if (options.transparent) {
688 window->setClearBeforeRendering(true);
689 window->setColor(QColor(Qt::transparent));
690 window->setFlags(Qt::FramelessWindowHint);
691 }
692 window->setFormat(surfaceFormat);
693
694 if (window->flags() == Qt::Window) // Fix window flags unless set by QML.
695 window->setFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowFullscreenButtonHint);
696
697 if (options.fullscreen)
698 window->showFullScreen();
699 else if (options.maximized)
700 window->showMaximized();
701 else if (!window->isVisible())
702 window->show();
703 }
704
705 if (options.quitImmediately)
706 QMetaObject::invokeMethod(obj: QCoreApplication::instance(), member: "quit", type: Qt::QueuedConnection);
707
708 // Now would be a good time to inform the debug service to start listening.
709
710 exitCode = app->exec();
711
712#ifdef QML_RUNTIME_TESTING
713 RenderStatistics::printTotalStats();
714#endif
715 // Ready to exit. Notice that the component might be owned by
716 // QQuickView if one was created. That case is tracked by
717 // QPointer, so it is safe to delete the component here.
718 delete component;
719 } else {
720 exitCode = 1;
721 }
722 }
723
724 return exitCode;
725}
726
727#include "main.moc"
728

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