forked from qt-creator/qt-creator
QmlDesigner: add support for multiple qml backends
This patch includes; * Fork of original QML runtime as an alternative QML backend for QDS * Flexible structure for adding/removing different types of QML interpreters Note: When forking the original QML the config.h is renamed as qmlconfiguration.h because it was clashing with sqlite and QmlRuntime.QmlConfiguration uses "magic" name matching. QmlConfiguration/qmlconfiguration is unlikely to conflict with anything. Task-number: QDS-8373 Change-Id: Ifaa1b766c717ce12d6b3c9ddbbc0665669797e36 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -35,7 +35,7 @@ QProcessUniquePointer puppetProcess(const QString &puppetPath,
|
||||
processFinishCallback);
|
||||
|
||||
if (forwardOutput == puppetMode || forwardOutput == "all") {
|
||||
puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
puppetProcess->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
QObject::connect(puppetProcess.get(), &QProcess::readyRead, processOutputCallback);
|
||||
}
|
||||
puppetProcess->setWorkingDirectory(workingDirectory);
|
||||
@@ -46,7 +46,6 @@ QProcessUniquePointer puppetProcess(const QString &puppetPath,
|
||||
else
|
||||
processArguments = {socketToken, puppetMode};
|
||||
|
||||
processArguments.push_back("-graphicssystem raster");
|
||||
processArguments.push_back(freeTypeOption);
|
||||
|
||||
puppetProcess->start(puppetPath, processArguments);
|
||||
|
@@ -35,12 +35,22 @@ add_qtc_executable(qml2puppet
|
||||
Qt5::QuickPrivate Qt5::Network Qt5::GuiPrivate
|
||||
QmlPuppetCommunication
|
||||
SOURCES
|
||||
qml2puppet/qml2puppetmain.cpp
|
||||
qml2puppet/main.cpp
|
||||
qmlpuppet.qrc
|
||||
)
|
||||
|
||||
set_target_properties(qml2puppet PROPERTIES OUTPUT_NAME qml2puppet-${IDE_VERSION})
|
||||
|
||||
execute_process(
|
||||
COMMAND git describe --tags --always --dirty=+
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_SHA_RESULT
|
||||
OUTPUT_VARIABLE GIT_SHA_OUTPUT
|
||||
ERROR_VARIABLE GIT_SHA_ERROR
|
||||
)
|
||||
|
||||
add_definitions( -D GIT_SHA=${GIT_SHA_OUTPUT} )
|
||||
|
||||
extend_qtc_executable(qml2puppet
|
||||
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0
|
||||
SOURCES
|
||||
@@ -166,6 +176,16 @@ extend_qtc_executable(qml2puppet
|
||||
animationdriver.cpp animationdriver.h
|
||||
)
|
||||
|
||||
extend_qtc_executable(qml2puppet
|
||||
DEPENDS app_version
|
||||
SOURCES_PREFIX qml2puppet/runner
|
||||
SOURCES
|
||||
runtime/qmlruntime.h runtime/qmlruntime.cpp
|
||||
runtime/qmlconfiguration.h runtime/loadwatcher.h
|
||||
puppet/qmlpuppet.h puppet/qmlpuppet.cpp puppet/configcrashpad.h
|
||||
qmlbase.h appmetadata.h
|
||||
)
|
||||
|
||||
extend_qtc_executable(qml2puppet
|
||||
SOURCES_PREFIX qmlprivategate
|
||||
SOURCES
|
||||
@@ -186,11 +206,21 @@ extend_qtc_executable(qml2puppet
|
||||
PUBLIC_INCLUDES src/libs
|
||||
)
|
||||
|
||||
extend_qtc_executable(qml2puppet
|
||||
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/qml2puppet/runner/runtime
|
||||
)
|
||||
|
||||
extend_qtc_executable(qml2puppet
|
||||
CONDITION TARGET Nanotrace
|
||||
DEPENDS Nanotrace
|
||||
)
|
||||
|
||||
# Turn the tool into its own self-contained qml module
|
||||
qt6_add_qml_module(qml2puppet
|
||||
URI QmlRuntime.QmlConfiguration
|
||||
VERSION 1.0
|
||||
)
|
||||
|
||||
if (QTC_STATIC_BUILD AND Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0)
|
||||
qt6_import_qml_plugins(qml2puppet PATH_TO_SCAN ${SRCDIR})
|
||||
endif()
|
||||
|
28
src/tools/qml2puppet/qml2puppet/main.cpp
Normal file
28
src/tools/qml2puppet/qml2puppet/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "runner/puppet/qmlpuppet.h"
|
||||
#include "runner/runtime/qmlruntime.h"
|
||||
|
||||
QmlBase *getQmlRunner(int &argc, char **argv)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--qml-runtime")){
|
||||
qInfo() << "Starting QML Runtime";
|
||||
return new QmlRuntime(argc, argv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
qInfo() << "Starting QML Puppet";
|
||||
return new QmlPuppet(argc, argv);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QDSMeta::Logging::registerMessageHandler();
|
||||
QDSMeta::AppInfo::registerAppInfo("Qml2Puppet");
|
||||
|
||||
QmlBase *qmlRunner = getQmlRunner(argc, argv);
|
||||
return qmlRunner->run();
|
||||
}
|
@@ -1,267 +0,0 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "iconrenderer/iconrenderer.h"
|
||||
#include "import3d/import3d.h"
|
||||
|
||||
#include <qt5nodeinstanceclientproxy.h>
|
||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||
#include <sqlitelibraryinitializer.h>
|
||||
#endif
|
||||
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlEngine>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QStringList>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef ENABLE_QT_BREAKPAD
|
||||
#include <qtsystemexceptionhandler.h>
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||
#define NOMINMAX
|
||||
#include "client/crashpad_client.h"
|
||||
#include "client/crash_report_database.h"
|
||||
#include "client/settings.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
{
|
||||
QByteArray localMsg = msg.toLocal8Bit();
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
fprintf(stderr,
|
||||
"Debug: %s (%s:%u, %s)\n",
|
||||
localMsg.constData(),
|
||||
context.file,
|
||||
context.line,
|
||||
context.function);
|
||||
break;
|
||||
case QtInfoMsg:
|
||||
fprintf(stderr,
|
||||
"Info: %s (%s:%u, %s)\n",
|
||||
localMsg.constData(),
|
||||
context.file,
|
||||
context.line,
|
||||
context.function);
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
fprintf(stderr,
|
||||
"Warning: %s (%s:%u, %s)\n",
|
||||
localMsg.constData(),
|
||||
context.file,
|
||||
context.line,
|
||||
context.function);
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
fprintf(stderr,
|
||||
"Critical: %s (%s:%u, %s)\n",
|
||||
localMsg.constData(),
|
||||
context.file,
|
||||
context.line,
|
||||
context.function);
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
fprintf(stderr,
|
||||
"Fatal: %s (%s:%u, %s)\n",
|
||||
localMsg.constData(),
|
||||
context.file,
|
||||
context.line,
|
||||
context.function);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||
bool startCrashpad()
|
||||
{
|
||||
using namespace crashpad;
|
||||
|
||||
// Cache directory that will store crashpad information and minidumps
|
||||
base::FilePath database(L"crashpad_reports");
|
||||
base::FilePath handler(L"crashpad_handler.exe");
|
||||
|
||||
// URL used to submit minidumps to
|
||||
std::string url(CRASHPAD_BACKEND_URL);
|
||||
|
||||
// Optional annotations passed via --annotations to the handler
|
||||
std::map<std::string, std::string> annotations;
|
||||
annotations["qt-version"] = QT_VERSION_STR;
|
||||
|
||||
// Optional arguments to pass to the handler
|
||||
std::vector<std::string> arguments;
|
||||
arguments.push_back("--no-rate-limit");
|
||||
|
||||
CrashpadClient *client = new CrashpadClient();
|
||||
bool success = client->StartHandler(
|
||||
handler,
|
||||
database,
|
||||
database,
|
||||
url,
|
||||
annotations,
|
||||
arguments,
|
||||
/* restartable */ true,
|
||||
/* asynchronous_start */ true
|
||||
);
|
||||
// TODO: research using this method, should avoid creating a separate CrashpadClient for the
|
||||
// puppet (needed only on windows according to docs).
|
||||
// client->SetHandlerIPCPipe(L"\\\\.\\pipe\\qml2puppet");
|
||||
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
|
||||
int internalMain(QGuiApplication *application)
|
||||
{
|
||||
QCoreApplication::setOrganizationName("QtProject");
|
||||
QCoreApplication::setOrganizationDomain("qt-project.org");
|
||||
QCoreApplication::setApplicationName("Qml2Puppet");
|
||||
QCoreApplication::setApplicationVersion("1.0.0");
|
||||
|
||||
if (application->arguments().count() < 2
|
||||
|| (application->arguments().at(1) == "--readcapturedstream" && application->arguments().count() < 3)
|
||||
|| (application->arguments().at(1) == "--rendericon" && application->arguments().count() < 5)
|
||||
|| (application->arguments().at(1) == "--import3dAsset" && application->arguments().count() < 6)) {
|
||||
qDebug() << "Usage:\n";
|
||||
qDebug() << "--test";
|
||||
qDebug() << "--version";
|
||||
qDebug() << "--readcapturedstream <stream file> [control stream file]";
|
||||
qDebug() << "--rendericon <icon size> <icon file name> <icon source qml>";
|
||||
qDebug() << "--import3dAsset <source asset file name> <output dir> <id number> <import options JSON>";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (application->arguments().at(1) == "--readcapturedstream" && application->arguments().count() > 2) {
|
||||
QFileInfo inputStreamFileInfo(application->arguments().at(2));
|
||||
if (!inputStreamFileInfo.exists()) {
|
||||
qDebug() << "Input stream does not exist:" << inputStreamFileInfo.absoluteFilePath();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (application->arguments().count() > 3) {
|
||||
QFileInfo controlStreamFileInfo(application->arguments().at(3));
|
||||
if (!controlStreamFileInfo.exists()) {
|
||||
qDebug() << "Output stream does not exist:" << controlStreamFileInfo.absoluteFilePath();
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (application->arguments().count() == 2 && application->arguments().at(1) == "--test") {
|
||||
qDebug() << QCoreApplication::applicationVersion();
|
||||
QQmlEngine engine;
|
||||
|
||||
QQmlComponent component(&engine);
|
||||
component.setData("import QtQuick 2.0\nItem {\n}\n", QUrl::fromLocalFile("test.qml"));
|
||||
|
||||
QObject *object = component.create();
|
||||
|
||||
if (object) {
|
||||
qDebug() << "Basic QtQuick 2.0 working...";
|
||||
} else {
|
||||
qDebug() << "Basic QtQuick 2.0 not working...";
|
||||
qDebug() << component.errorString();
|
||||
}
|
||||
delete object;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (application->arguments().count() == 2 && application->arguments().at(1) == "--version") {
|
||||
std::cout << 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (application->arguments().at(1) != "--readcapturedstream" && application->arguments().count() < 4) {
|
||||
qDebug() << "Wrong argument count: " << application->arguments().count();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (application->arguments().at(1) == "--rendericon") {
|
||||
int size = application->arguments().at(2).toInt();
|
||||
QString iconFileName = application->arguments().at(3);
|
||||
QString iconSource = application->arguments().at(4);
|
||||
|
||||
IconRenderer *iconRenderer = new IconRenderer(size, iconFileName, iconSource);
|
||||
iconRenderer->setupRender();
|
||||
|
||||
return application->exec();
|
||||
}
|
||||
|
||||
if (application->arguments().at(1) == "--import3dAsset") {
|
||||
QString sourceAsset = application->arguments().at(2);
|
||||
QString outDir = application->arguments().at(3);
|
||||
QString options = application->arguments().at(4);
|
||||
|
||||
Import3D::import3D(sourceAsset, outDir, options);
|
||||
|
||||
return application->exec();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_QT_BREAKPAD
|
||||
const QString libexecPath = QCoreApplication::applicationDirPath() + '/' + RELATIVE_LIBEXEC_PATH;
|
||||
QtSystemExceptionHandler systemExceptionHandler(libexecPath);
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||
/* startCrashpad(); */
|
||||
#endif
|
||||
|
||||
new QmlDesigner::Qt5NodeInstanceClientProxy(application);
|
||||
|
||||
#if defined(Q_OS_WIN) && defined(QT_NO_DEBUG)
|
||||
SetErrorMode(SEM_NOGPFAULTERRORBOX); //We do not want to see any message boxes
|
||||
#endif
|
||||
|
||||
if (application->arguments().at(1) == "--readcapturedstream")
|
||||
return 0;
|
||||
|
||||
return application->exec();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
qInstallMessageHandler(myMessageOutput);
|
||||
#endif
|
||||
// Since we always render text into an FBO, we need to globally disable
|
||||
// subpixel antialiasing and instead use gray.
|
||||
qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray");
|
||||
#ifdef Q_OS_MACOS
|
||||
qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "true");
|
||||
#endif
|
||||
|
||||
//If a style different from Desktop is set we have to use QGuiApplication
|
||||
bool useGuiApplication = (!qEnvironmentVariableIsSet("QMLDESIGNER_FORCE_QAPPLICATION")
|
||||
|| qgetenv("QMLDESIGNER_FORCE_QAPPLICATION") != "true")
|
||||
&& qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_STYLE")
|
||||
&& qgetenv("QT_QUICK_CONTROLS_STYLE") != "Desktop";
|
||||
|
||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||
Sqlite::LibraryInitializer::initialize();
|
||||
#endif
|
||||
|
||||
if (useGuiApplication) {
|
||||
QGuiApplication application(argc, argv);
|
||||
return internalMain(&application);
|
||||
} else {
|
||||
QApplication application(argc, argv);
|
||||
return internalMain(&application);
|
||||
}
|
||||
}
|
99
src/tools/qml2puppet/qml2puppet/runner/appmetadata.h
Normal file
99
src/tools/qml2puppet/qml2puppet/runner/appmetadata.h
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH
|
||||
// Qt-GPL-exception-1.0
|
||||
#pragma once
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include <app/app_version.h>
|
||||
|
||||
// Common functions can be used in all QDS apps
|
||||
namespace QDSMeta {
|
||||
|
||||
namespace Logging {
|
||||
inline Q_LOGGING_CATEGORY(deprecated, "qt.tools.qds.deprecated");
|
||||
inline Q_LOGGING_CATEGORY(verbose1, "qt.tools.qds.verbose1");
|
||||
inline Q_LOGGING_CATEGORY(verbose2, "qt.tools.qds.verbose2");
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
inline void registerMessageHandler()
|
||||
{
|
||||
qInstallMessageHandler(
|
||||
[](QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||
auto tPrinter = [&](const QString &msgPrefix) {
|
||||
fprintf(stderr,
|
||||
"%s: %s (%s:%u, %s)\n",
|
||||
msgPrefix.toLocal8Bit().constData(),
|
||||
msg.toLocal8Bit().constData(),
|
||||
context.file,
|
||||
context.line,
|
||||
context.function);
|
||||
};
|
||||
|
||||
if (type == QtDebugMsg)
|
||||
tPrinter("Debug");
|
||||
else if (type == QtInfoMsg)
|
||||
tPrinter("Info");
|
||||
else if (type == QtWarningMsg)
|
||||
tPrinter("Warning");
|
||||
else if (type == QtCriticalMsg)
|
||||
tPrinter("Critical");
|
||||
else if (type == QtFatalMsg) {
|
||||
tPrinter("Fatal");
|
||||
abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Logging
|
||||
|
||||
namespace AppInfo {
|
||||
|
||||
#define STRINGIFY_INTERNAL(x) #x
|
||||
#define QDS_STRINGIFY(x) STRINGIFY_INTERNAL(x)
|
||||
|
||||
inline void printAppInfo()
|
||||
{
|
||||
qInfo() << Qt::endl
|
||||
<< "<< QDS Meta Info >>" << Qt::endl
|
||||
<< "App Info" << Qt::endl
|
||||
<< " - Name :" << Core::Constants::IDE_ID << Qt::endl
|
||||
<< " - Version :" << Core::Constants::IDE_VERSION_DISPLAY << Qt::endl
|
||||
<< " - Author :" << Core::Constants::IDE_AUTHOR << Qt::endl
|
||||
<< " - Year :" << Core::Constants::IDE_YEAR << Qt::endl
|
||||
<< " - App :" << QCoreApplication::applicationName() << Qt::endl
|
||||
<< "Build Info " << Qt::endl
|
||||
<< " - Date :" << __DATE__ << Qt::endl
|
||||
<< " - Commit :" << QStringLiteral(QDS_STRINGIFY(GIT_SHA)) << Qt::endl
|
||||
<< " - Qt Version :" << QT_VERSION_STR << Qt::endl
|
||||
<< "Compiler Info " << Qt::endl
|
||||
#if defined(__GNUC__)
|
||||
<< " - GCC :" << __GNUC__ << Qt::endl
|
||||
<< " - GCC Minor :" << __GNUC_MINOR__ << Qt::endl
|
||||
<< " - GCC Patch :" << __GNUC_PATCHLEVEL__ << Qt::endl
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
<< " - MSC Short :" << _MSC_VER << Qt::endl
|
||||
<< " - MSC Full :" << _MSC_FULL_VER << Qt::endl
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
<< " - clang maj :" << __clang_major__ << Qt::endl
|
||||
<< " - clang min :" << __clang_minor__ << Qt::endl
|
||||
<< " - clang patch :" << __clang_patchlevel__ << Qt::endl
|
||||
#endif
|
||||
<< "<< End Of QDS Meta Info >>" << Qt::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
inline void registerAppInfo(const QString &appName)
|
||||
{
|
||||
QCoreApplication::setOrganizationName(Core::Constants::IDE_AUTHOR);
|
||||
QCoreApplication::setOrganizationDomain("qt-project.org");
|
||||
QCoreApplication::setApplicationName(appName);
|
||||
QCoreApplication::setApplicationVersion(Core::Constants::IDE_VERSION_LONG);
|
||||
}
|
||||
|
||||
} // namespace AppInfo
|
||||
} // namespace QDSMeta
|
@@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
#pragma once
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#define START_CRASHPAD
|
||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||
startCrashpad()
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_QT_BREAKPAD
|
||||
#include <qtsystemexceptionhandler.h>
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||
#define NOMINMAX
|
||||
#include "client/crash_report_database.h"
|
||||
#include "client/crashpad_client.h"
|
||||
#include "client/settings.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||
bool startCrashpad()
|
||||
{
|
||||
using namespace crashpad;
|
||||
|
||||
// Cache directory that will store crashpad information and minidumps
|
||||
base::FilePath database(L"crashpad_reports");
|
||||
base::FilePath handler(L"crashpad_handler.exe");
|
||||
|
||||
// URL used to submit minidumps to
|
||||
std::string url(CRASHPAD_BACKEND_URL);
|
||||
|
||||
// Optional annotations passed via --annotations to the handler
|
||||
std::map<std::string, std::string> annotations;
|
||||
annotations["qt-version"] = QT_VERSION_STR;
|
||||
|
||||
// Optional arguments to pass to the handler
|
||||
std::vector<std::string> arguments;
|
||||
arguments.push_back("--no-rate-limit");
|
||||
|
||||
CrashpadClient *client = new CrashpadClient();
|
||||
bool success = client->StartHandler(handler,
|
||||
database,
|
||||
database,
|
||||
url,
|
||||
annotations,
|
||||
arguments,
|
||||
/* restartable */ true,
|
||||
/* asynchronous_start */ true);
|
||||
// TODO: research using this method, should avoid creating a separate CrashpadClient for the
|
||||
// puppet (needed only on windows according to docs).
|
||||
// client->SetHandlerIPCPipe(L"\\\\.\\pipe\\qml2puppet");
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_QT_BREAKPAD
|
||||
const QString libexecPath = QCoreApplication::applicationDirPath() + '/'
|
||||
+ RELATIVE_LIBEXEC_PATH;
|
||||
QtSystemExceptionHandler systemExceptionHandler(libexecPath);
|
||||
#endif
|
||||
#endif
|
||||
}
|
126
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.cpp
Normal file
126
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qmlpuppet.h"
|
||||
|
||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||
#include <sqlitelibraryinitializer.h>
|
||||
#endif
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "qml2puppet/iconrenderer/iconrenderer.h"
|
||||
#include "qml2puppet/import3d/import3d.h"
|
||||
|
||||
#include "configcrashpad.h"
|
||||
|
||||
#include <qt5nodeinstanceclientproxy.h>
|
||||
|
||||
void QmlPuppet::initCoreApp()
|
||||
{
|
||||
// Since we always render text into an FBO, we need to globally disable
|
||||
// subpixel antialiasing and instead use gray.
|
||||
qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray");
|
||||
#ifdef Q_OS_MACOS
|
||||
qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "true");
|
||||
#endif
|
||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||
Sqlite::LibraryInitializer::initialize();
|
||||
#endif
|
||||
|
||||
//If a style different from Desktop is set we have to use QGuiApplication
|
||||
bool useGuiApplication = (!qEnvironmentVariableIsSet("QMLDESIGNER_FORCE_QAPPLICATION")
|
||||
|| qgetenv("QMLDESIGNER_FORCE_QAPPLICATION") != "true")
|
||||
&& qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_STYLE")
|
||||
&& qgetenv("QT_QUICK_CONTROLS_STYLE") != "Desktop";
|
||||
#ifndef QT_GUI_LIB
|
||||
createCoreApp<QCoreApplication>();
|
||||
#else
|
||||
#if defined QT_WIDGETS_LIB
|
||||
if (!useGuiApplication)
|
||||
createCoreApp<QApplication>();
|
||||
else
|
||||
#endif //QT_WIDGETS_LIB
|
||||
createCoreApp<QGuiApplication>();
|
||||
#endif //QT_GUI_LIB
|
||||
}
|
||||
|
||||
int QmlPuppet::startTestMode()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QQmlComponent component(&engine);
|
||||
component.setData("import QtQuick 2.0\nItem {\n}\n", QUrl::fromLocalFile("test.qml"));
|
||||
|
||||
if (!QSharedPointer<QObject>(component.create())) {
|
||||
qDebug() << "Basic QtQuick 2.0 not working...";
|
||||
qDebug() << component.errorString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
qDebug() << "Basic QtQuick 2.0 working...";
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QmlPuppet::populateParser()
|
||||
{
|
||||
// we're not using the commandline parser but just populating the help text
|
||||
m_argParser.addOptions(
|
||||
{{"readcapturedstream", "Read captured stream.", "inputStream, [outputStream]"},
|
||||
{"rendericon", "Renders icon.", "size, fileName, sourceQml"},
|
||||
{"import3dAsset", "Import 3d asset.", "sourceAsset, outDir, importOptJson"}});
|
||||
}
|
||||
|
||||
void QmlPuppet::initQmlRunner()
|
||||
{
|
||||
if (m_coreApp->arguments().count() < 2
|
||||
|| (m_argParser.isSet("readcapturedstream") && m_coreApp->arguments().count() < 3)
|
||||
|| (m_argParser.isSet("rendericon") && m_coreApp->arguments().count() < 5)
|
||||
|| (m_argParser.isSet("import3dAsset") && m_coreApp->arguments().count() < 6)
|
||||
|| (!m_argParser.isSet("readcapturedstream") && m_coreApp->arguments().count() < 4)) {
|
||||
qDebug() << "Wrong argument count: " << m_coreApp->arguments().count();
|
||||
m_argParser.showHelp(1);
|
||||
}
|
||||
|
||||
if (m_argParser.isSet("readcapturedstream") && m_coreApp->arguments().count() > 2) {
|
||||
QString fileName = m_argParser.value("readcapturedstream");
|
||||
if (!QFile::exists(fileName)) {
|
||||
qDebug() << "Input stream does not exist:" << fileName;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (m_coreApp->arguments().count() > 3) {
|
||||
fileName = m_coreApp->arguments().at(3);
|
||||
if (!QFile::exists(fileName)) {
|
||||
qDebug() << "Output stream does not exist:" << fileName;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_argParser.isSet("rendericon")) {
|
||||
int size = m_coreApp->arguments().at(2).toInt();
|
||||
QString iconFileName = m_coreApp->arguments().at(3);
|
||||
QString iconSource = m_coreApp->arguments().at(4);
|
||||
|
||||
m_iconRenderer.reset(new IconRenderer(size, iconFileName, iconSource));
|
||||
m_iconRenderer->setupRender();
|
||||
} else if (m_argParser.isSet("import3dAsset")) {
|
||||
QString sourceAsset = m_coreApp->arguments().at(2);
|
||||
QString outDir = m_coreApp->arguments().at(3);
|
||||
QString options = m_coreApp->arguments().at(4);
|
||||
|
||||
Import3D::import3D(sourceAsset, outDir, options);
|
||||
}
|
||||
|
||||
START_CRASHPAD;
|
||||
new QmlDesigner::Qt5NodeInstanceClientProxy(m_coreApp.get());
|
||||
|
||||
#if defined(Q_OS_WIN) && defined(QT_NO_DEBUG)
|
||||
SetErrorMode(SEM_NOGPFAULTERRORBOX); //We do not want to see any message boxes
|
||||
#endif
|
||||
|
||||
if (m_argParser.isSet("readcapturedstream"))
|
||||
exit(0);
|
||||
}
|
21
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.h
Normal file
21
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../qmlbase.h"
|
||||
|
||||
class IconRenderer;
|
||||
class QmlPuppet : public QmlBase
|
||||
{
|
||||
using QmlBase::QmlBase;
|
||||
|
||||
private:
|
||||
void initCoreApp() override;
|
||||
void populateParser() override;
|
||||
int startTestMode() override;
|
||||
void initQmlRunner() override;
|
||||
|
||||
private:
|
||||
QSharedPointer<IconRenderer> m_iconRenderer;
|
||||
};
|
111
src/tools/qml2puppet/qml2puppet/runner/qmlbase.h
Normal file
111
src/tools/qml2puppet/qml2puppet/runner/qmlbase.h
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH
|
||||
// Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDir>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QFileOpenEvent>
|
||||
#include <QLibraryInfo>
|
||||
#include <QSurfaceFormat>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "appmetadata.h"
|
||||
#include <iostream>
|
||||
|
||||
#include <QApplication>
|
||||
class QmlBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct AppArgs
|
||||
{
|
||||
public:
|
||||
int argc;
|
||||
char **argv;
|
||||
};
|
||||
|
||||
QmlBase(int &argc, char **argv, QObject *parent = nullptr)
|
||||
: QObject{parent}
|
||||
, m_args({argc, argv})
|
||||
{
|
||||
m_argParser.setApplicationDescription("QML Runtime Provider for QDS");
|
||||
m_argParser.addOptions(
|
||||
{{"qml-puppet", "Run QML Puppet (default)"},
|
||||
{"qml-runtime", "Run QML Runtime"},
|
||||
{"appinfo", "Print build information"},
|
||||
{"test", "Run test mode"}
|
||||
});
|
||||
}
|
||||
|
||||
int run()
|
||||
{
|
||||
populateParser();
|
||||
initCoreApp();
|
||||
initParser();
|
||||
initQmlRunner();
|
||||
return m_coreApp->exec();
|
||||
}
|
||||
|
||||
QSharedPointer<QCoreApplication> coreApp() const { return m_coreApp; }
|
||||
|
||||
protected:
|
||||
virtual void initCoreApp() = 0;
|
||||
virtual void populateParser() = 0;
|
||||
virtual void initQmlRunner() = 0;
|
||||
|
||||
virtual int startTestMode()
|
||||
{
|
||||
qDebug() << "Test mode is not implemented for this type of runner";
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void createCoreApp()
|
||||
{
|
||||
m_coreApp.reset(new T(m_args.argc, m_args.argv));
|
||||
}
|
||||
|
||||
QSharedPointer<QCoreApplication> m_coreApp;
|
||||
QCommandLineParser m_argParser;
|
||||
QSharedPointer<QQmlApplicationEngine> m_qmlEngine;
|
||||
|
||||
AppArgs m_args;
|
||||
|
||||
private:
|
||||
void initParser()
|
||||
{
|
||||
QCommandLineOption optHelp = m_argParser.addHelpOption();
|
||||
QCommandLineOption optVers = m_argParser.addVersionOption();
|
||||
|
||||
if (!m_coreApp) {
|
||||
qCritical() << "Cannot initialize coreapp!";
|
||||
m_argParser.showHelp();
|
||||
}
|
||||
|
||||
if (!m_argParser.parse(m_coreApp->arguments())) {
|
||||
std::cout << "Error: " << m_argParser.errorText().toStdString() << std::endl
|
||||
<< std::endl;
|
||||
m_argParser.showHelp(1);
|
||||
} else if (m_argParser.isSet(optVers)) {
|
||||
m_argParser.showVersion();
|
||||
} else if (m_argParser.isSet(optHelp)) {
|
||||
m_argParser.showHelp(0);
|
||||
} else if (m_argParser.isSet("appinfo")) {
|
||||
QDSMeta::AppInfo::printAppInfo();
|
||||
} else if (m_argParser.isSet("test")) {
|
||||
exit(startTestMode());
|
||||
}
|
||||
}
|
||||
};
|
97
src/tools/qml2puppet/qml2puppet/runner/runtime/loadwatcher.h
Normal file
97
src/tools/qml2puppet/qml2puppet/runner/runtime/loadwatcher.h
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "qmlconfiguration.h"
|
||||
|
||||
#include "QtQml/qqmlcomponent.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
//// Listens to the appEngine signals to determine if all files failed to load
|
||||
class LoadWatcher : public QObject
|
||||
{
|
||||
// Q_OBJECT
|
||||
public:
|
||||
LoadWatcher(QQmlApplicationEngine *e, int expected, Config *conf)
|
||||
: QObject(e)
|
||||
, qae(e)
|
||||
, conf(conf)
|
||||
, expectedFileCount(expected)
|
||||
{
|
||||
connect(e, &QQmlApplicationEngine::objectCreated, this, &LoadWatcher::checkFinished);
|
||||
// QQmlApplicationEngine also connects quit() to QCoreApplication::quit
|
||||
// and exit() to QCoreApplication::exit but if called before exec()
|
||||
// then QCoreApplication::quit or QCoreApplication::exit does nothing
|
||||
connect(e, &QQmlEngine::quit, this, &LoadWatcher::quit);
|
||||
connect(e, &QQmlEngine::exit, this, &LoadWatcher::exit);
|
||||
}
|
||||
|
||||
int returnCode = 0;
|
||||
bool earlyExit = false;
|
||||
|
||||
public Q_SLOTS:
|
||||
void checkFinished(QObject *o, const QUrl &url)
|
||||
{
|
||||
Q_UNUSED(url);
|
||||
if (o) {
|
||||
checkForWindow(o);
|
||||
if (conf && qae) {
|
||||
for (PartialScene *ps : std::as_const(conf->completers)) {
|
||||
if (o->inherits(ps->itemType().toUtf8().constData()))
|
||||
contain(o, ps->container());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (haveWindow)
|
||||
return;
|
||||
|
||||
if (!--expectedFileCount) {
|
||||
printf("qml: Did not load any objects, exiting.\n");
|
||||
exit(2);
|
||||
QCoreApplication::exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
// Will be checked before calling exec()
|
||||
earlyExit = true;
|
||||
returnCode = 0;
|
||||
}
|
||||
void exit(int retCode)
|
||||
{
|
||||
earlyExit = true;
|
||||
returnCode = retCode;
|
||||
}
|
||||
|
||||
private:
|
||||
void contain(QObject *o, const QUrl &containPath)
|
||||
{
|
||||
QQmlComponent c(qae, containPath);
|
||||
QObject *o2 = c.create();
|
||||
if (!o2)
|
||||
return;
|
||||
o2->setParent(this);
|
||||
checkForWindow(o2);
|
||||
bool success = false;
|
||||
int idx;
|
||||
if ((idx = o2->metaObject()->indexOfProperty("containedObject")) != -1)
|
||||
success = o2->metaObject()->property(idx).write(o2, QVariant::fromValue<QObject *>(o));
|
||||
if (!success)
|
||||
o->setParent(o2); // Set QObject parent, and assume container will react as needed
|
||||
}
|
||||
void checkForWindow(QObject *o)
|
||||
{
|
||||
if (o->isWindowType() && o->inherits("QQuickWindow"))
|
||||
haveWindow = true;
|
||||
}
|
||||
|
||||
private:
|
||||
QQmlApplicationEngine *qae;
|
||||
Config *conf;
|
||||
|
||||
bool haveWindow = false;
|
||||
int expectedFileCount;
|
||||
};
|
@@ -0,0 +1,66 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QUrl>
|
||||
#include <QtQml/qqml.h>
|
||||
|
||||
class PartialScene : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QUrl container READ container WRITE setContainer NOTIFY containerChanged)
|
||||
Q_PROPERTY(QString itemType READ itemType WRITE setItemType NOTIFY itemTypeChanged)
|
||||
QML_ELEMENT
|
||||
QML_ADDED_IN_VERSION(1, 0)
|
||||
public:
|
||||
PartialScene(QObject *parent = nullptr)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
const QUrl container() const { return m_container; }
|
||||
const QString itemType() const { return m_itemType; }
|
||||
|
||||
void setContainer(const QUrl &a)
|
||||
{
|
||||
if (a == m_container)
|
||||
return;
|
||||
m_container = a;
|
||||
emit containerChanged();
|
||||
}
|
||||
void setItemType(const QString &a)
|
||||
{
|
||||
if (a == m_itemType)
|
||||
return;
|
||||
m_itemType = a;
|
||||
emit itemTypeChanged();
|
||||
}
|
||||
|
||||
signals:
|
||||
void containerChanged();
|
||||
void itemTypeChanged();
|
||||
|
||||
private:
|
||||
QUrl m_container;
|
||||
QString m_itemType;
|
||||
};
|
||||
|
||||
class Config : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QQmlListProperty<PartialScene> sceneCompleters READ sceneCompleters)
|
||||
Q_CLASSINFO("DefaultProperty", "sceneCompleters")
|
||||
QML_NAMED_ELEMENT(Configuration)
|
||||
QML_ADDED_IN_VERSION(1, 0)
|
||||
public:
|
||||
Config(QObject *parent = nullptr)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
QQmlListProperty<PartialScene> sceneCompleters()
|
||||
{
|
||||
return QQmlListProperty<PartialScene>(this, &completers);
|
||||
}
|
||||
|
||||
QList<PartialScene *> completers;
|
||||
};
|
348
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.cpp
Normal file
348
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
#include "loadwatcher.h"
|
||||
#include "qmlruntime.h"
|
||||
|
||||
#include <private/qqmlimport_p.h>
|
||||
#include <private/qtqmlglobal_p.h>
|
||||
#if QT_CONFIG(qml_animation)
|
||||
#include <private/qabstractanimation_p.h>
|
||||
#endif
|
||||
|
||||
#define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms
|
||||
#define QSL QStringLiteral
|
||||
|
||||
void QmlRuntime::populateParser()
|
||||
{
|
||||
m_argParser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||
m_argParser.setOptionsAfterPositionalArgumentsMode(
|
||||
QCommandLineParser::ParseAsPositionalArguments);
|
||||
|
||||
m_argParser.addOptions(
|
||||
{{QStringList() << QSL("a") << QSL("apptype"),
|
||||
QSL("Select which application class to use. Default is gui."),
|
||||
QSL("core|gui|widget")}, // just for translation
|
||||
|
||||
{QSL("I"), QSL("Prepend the given path to the import paths."), QSL("path")},
|
||||
|
||||
{QSL("f"), QSL("Load the given file as a QML file."), QSL("file")},
|
||||
|
||||
{QStringList() << QSL("c") << QSL("config"),
|
||||
QSL("Load the given built-in configuration or configuration file."),
|
||||
QSL("file")},
|
||||
|
||||
{QStringList() << QSL("list-conf"), QSL("List the built-in configurations.")},
|
||||
|
||||
{QSL("translation"), QSL("Load the given file as the translations file."), QSL("file")},
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
// OpenGL options
|
||||
{QSL("desktop"), QSL("Force use of desktop OpenGL (AA_UseDesktopOpenGL).")},
|
||||
|
||||
{QSL("gles"), QSL("Force use of GLES (AA_UseOpenGLES).")},
|
||||
|
||||
{QSL("software"), QSL("Force use of software rendering (AA_UseSoftwareOpenGL).")},
|
||||
|
||||
{QSL("core-profile"), QSL("Force use of OpenGL Core Profile.")},
|
||||
|
||||
{QSL("disable-context-sharing"),
|
||||
QSL("Disable the use of a shared GL context for QtQuick Windows")},
|
||||
#endif // QT_GUI_LIB
|
||||
|
||||
// Debugging and verbosity options
|
||||
{QSL("quiet"), QSL("Suppress all output.")},
|
||||
|
||||
{QSL("verbose"),
|
||||
QSL("Print information about what qml is doing, like specific file URLs being loaded.")},
|
||||
|
||||
{QSL("slow-animations"), QSL("Run all animations in slow motion.")},
|
||||
|
||||
{QSL("fixed-animations"), QSL("Run animations off animation tick rather than wall time.")},
|
||||
|
||||
{QStringList() << QSL("r") << QSL("rhi"),
|
||||
QSL("Set the backend for the Qt graphics abstraction (RHI). "
|
||||
"Backend is one of: default, vulkan, metal, d3d11, gl"),
|
||||
QSL("backend")},
|
||||
|
||||
{QSL("S"), QSL("Add selector to the list of QQmlFileSelectors."), QSL("selector")}});
|
||||
|
||||
// Positional arguments
|
||||
m_argParser.addPositionalArgument(
|
||||
"files",
|
||||
QSL("Any number of QML files can be loaded. They will share the same engine."),
|
||||
"[files...]");
|
||||
m_argParser.addPositionalArgument("args",
|
||||
QSL("Arguments after '--' are ignored, but passed through to "
|
||||
"the application.arguments variable in QML."),
|
||||
"[-- args...]");
|
||||
}
|
||||
|
||||
void QmlRuntime::initCoreApp()
|
||||
{
|
||||
bool glShareContexts = true;
|
||||
|
||||
// these attributes must be set before the QCoreApp is initialized
|
||||
for (int i = 0; i < m_args.argc; i++) {
|
||||
if (!strcmp(m_args.argv[i], "-desktop") || !strcmp(m_args.argv[i], "--desktop")) {
|
||||
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||
} else if (!strcmp(m_args.argv[i], "-gles") || !strcmp(m_args.argv[i], "--gles")) {
|
||||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
} else if (!strcmp(m_args.argv[i], "-software") || !strcmp(m_args.argv[i], "--software")) {
|
||||
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
|
||||
} else if (!strcmp(m_args.argv[i], "-disable-context-sharing")
|
||||
|| !strcmp(m_args.argv[i], "--disable-context-sharing")) {
|
||||
glShareContexts = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (glShareContexts)
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
|
||||
// since we handled all attributes above, now we can initialize the core app
|
||||
for (int i = 0; i < m_args.argc; i++) {
|
||||
if (!strcmp(m_args.argv[i], "--apptype") || !strcmp(m_args.argv[i], "-a")
|
||||
|| !strcmp(m_args.argv[i], "-apptype")) {
|
||||
if (i + 1 < m_args.argc) {
|
||||
++i;
|
||||
if (!strcmp(m_args.argv[i], "core")) {
|
||||
createCoreApp<QCoreApplication>();
|
||||
}
|
||||
else if (!strcmp(m_args.argv[i], "gui")) {
|
||||
createCoreApp<QGuiApplication>();
|
||||
}
|
||||
#ifdef QT_WIDGETS_LIB
|
||||
else if (!strcmp(m_args.argv[i], "widget")) {
|
||||
createCoreApp<QApplication>();
|
||||
static_cast<QApplication *>(m_coreApp.get())
|
||||
->setWindowIcon(QIcon(m_iconResourcePath));
|
||||
}
|
||||
#endif // QT_WIDGETS_LIB
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlRuntime::initQmlRunner()
|
||||
{
|
||||
m_qmlEngine.reset(new QQmlApplicationEngine());
|
||||
|
||||
QStringList files;
|
||||
QString confFile;
|
||||
QString translationFile;
|
||||
|
||||
if (!m_argParser.parse(QCoreApplication::arguments())) {
|
||||
qWarning() << m_argParser.errorText();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// TODO: replace below logging modes with a proper logging category
|
||||
m_verboseMode = m_argParser.isSet("verbose");
|
||||
m_quietMode = (!m_verboseMode && m_argParser.isSet("quiet"));
|
||||
// FIXME: need to re-evaluate. we have our own message handler.
|
||||
// if (quietMode) {
|
||||
// qInstallMessageHandler(quietMessageHandler);
|
||||
// QLoggingCategory::setFilterRules(QStringLiteral("*=false"));
|
||||
// }
|
||||
|
||||
if (m_argParser.isSet("list-conf")) {
|
||||
listConfFiles();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(qml_animation)
|
||||
if (m_argParser.isSet("slow-animations"))
|
||||
QUnifiedTimer::instance()->setSlowModeEnabled(true);
|
||||
if (m_argParser.isSet("fixed-animations"))
|
||||
QUnifiedTimer::instance()->setConsistentTiming(true);
|
||||
#endif
|
||||
const auto valsImportPath = m_argParser.values("I");
|
||||
for (const QString &importPath : valsImportPath)
|
||||
m_qmlEngine->addImportPath(importPath);
|
||||
|
||||
QStringList customSelectors;
|
||||
|
||||
const auto valsSelectors = m_argParser.values("S");
|
||||
for (const QString &selector : valsSelectors)
|
||||
customSelectors.append(selector);
|
||||
|
||||
if (!customSelectors.isEmpty())
|
||||
m_qmlEngine->setExtraFileSelectors(customSelectors);
|
||||
|
||||
if (qEnvironmentVariableIsSet("QSG_CORE_PROFILE")
|
||||
|| qEnvironmentVariableIsSet("QML_CORE_PROFILE") || m_argParser.isSet("core-profile")) {
|
||||
QSurfaceFormat surfaceFormat;
|
||||
surfaceFormat.setStencilBufferSize(8);
|
||||
surfaceFormat.setDepthBufferSize(24);
|
||||
surfaceFormat.setVersion(4, 1);
|
||||
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
|
||||
QSurfaceFormat::setDefaultFormat(surfaceFormat);
|
||||
}
|
||||
|
||||
if (m_argParser.isSet("config"))
|
||||
confFile = m_argParser.value("config");
|
||||
if (m_argParser.isSet("translation"))
|
||||
translationFile = m_argParser.value("translation");
|
||||
if (m_argParser.isSet("rhi")) {
|
||||
const QString rhiBackend = m_argParser.value("rhi");
|
||||
if (rhiBackend == QLatin1String("default"))
|
||||
qunsetenv("QSG_RHI_BACKEND");
|
||||
else
|
||||
qputenv("QSG_RHI_BACKEND", rhiBackend.toLatin1());
|
||||
}
|
||||
|
||||
const auto valsPosArgs = m_argParser.positionalArguments();
|
||||
files << m_argParser.values("f");
|
||||
for (const QString &posArg : valsPosArgs) {
|
||||
if (posArg == QLatin1String("--"))
|
||||
break;
|
||||
else
|
||||
files << posArg;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(translation)
|
||||
// Need to be installed before QQmlApplicationEngine's automatic translation loading
|
||||
// (qt_ translations are loaded there)
|
||||
if (!translationFile.isEmpty()) {
|
||||
QTranslator translator;
|
||||
|
||||
if (translator.load(translationFile)) {
|
||||
m_coreApp->installTranslator(&translator);
|
||||
if (m_verboseMode)
|
||||
qInfo() << "qml: Loaded translation file %s\n",
|
||||
qPrintable(QDir::toNativeSeparators(translationFile));
|
||||
} else {
|
||||
if (!m_quietMode)
|
||||
qInfo() << "qml: Could not load the translation file %s\n",
|
||||
qPrintable(QDir::toNativeSeparators(translationFile));
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!translationFile.isEmpty() && !quietMode)
|
||||
qInfo() << "qml: Translation file specified, but Qt built without translation support.\n");
|
||||
#endif
|
||||
|
||||
if (files.size() <= 0) {
|
||||
#if defined(Q_OS_DARWIN)
|
||||
if (qobject_cast<QGuiApplication *>(m_coreApp.data())) {
|
||||
m_exitTimerId = static_cast<QGuiApplication *>(m_coreApp.get())
|
||||
->startTimer(FILE_OPEN_EVENT_WAIT_TIME);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!m_quietMode)
|
||||
qCritical() << "No files specified. Terminating.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
loadConf(confFile, !m_verboseMode);
|
||||
|
||||
// Load files
|
||||
QScopedPointer<LoadWatcher> lw(new LoadWatcher(m_qmlEngine.data(), files.size(), m_conf.data()));
|
||||
|
||||
for (const QString &path : std::as_const(files)) {
|
||||
QUrl url = QUrl::fromUserInput(path, QDir::currentPath(), QUrl::AssumeLocalFile);
|
||||
if (m_verboseMode)
|
||||
qInfo() << "qml: loading %s\n", qPrintable(url.toString());
|
||||
m_qmlEngine->load(url);
|
||||
}
|
||||
|
||||
if (lw->earlyExit)
|
||||
exit(lw->returnCode);
|
||||
}
|
||||
|
||||
void QmlRuntime::loadConf(const QString &override, bool quiet) // Terminates app on failure
|
||||
{
|
||||
const QString defaultFileName = QLatin1String("default.qml");
|
||||
QUrl settingsUrl;
|
||||
bool builtIn = false; //just for keeping track of the warning
|
||||
if (override.isEmpty()) {
|
||||
QFileInfo fi;
|
||||
fi.setFile(QStandardPaths::locate(QStandardPaths::AppDataLocation, defaultFileName));
|
||||
if (fi.exists()) {
|
||||
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||
} else {
|
||||
// If different built-in configs are needed per-platform, just apply QFileSelector to the qrc conf.qml path
|
||||
fi.setFile(m_confResourcePath + defaultFileName);
|
||||
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||
builtIn = true;
|
||||
}
|
||||
} else {
|
||||
QFileInfo fi;
|
||||
fi.setFile(m_confResourcePath + override + QLatin1String(".qml"));
|
||||
if (fi.exists()) {
|
||||
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||
builtIn = true;
|
||||
} else {
|
||||
fi.setFile(QDir(QStandardPaths::locate(QStandardPaths::AppConfigLocation,
|
||||
override,
|
||||
QStandardPaths::LocateDirectory)),
|
||||
m_confResourcePath);
|
||||
if (fi.exists())
|
||||
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||
else
|
||||
fi.setFile(override);
|
||||
if (!fi.exists()) {
|
||||
qCritical() << "qml: Couldn't find required configuration file: %s\n",
|
||||
qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
||||
exit(1);
|
||||
}
|
||||
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
if (!quiet) {
|
||||
qInfo() << "qml: %s\n", QLibraryInfo::build();
|
||||
if (builtIn) {
|
||||
qInfo() << "qml: Using built-in configuration: %s\n",
|
||||
qPrintable(override.isEmpty() ? defaultFileName : override);
|
||||
} else {
|
||||
qInfo() << "qml: Using configuration: %s\n",
|
||||
qPrintable(settingsUrl.isLocalFile()
|
||||
? QDir::toNativeSeparators(settingsUrl.toLocalFile())
|
||||
: settingsUrl.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: When we have better engine control, ban QtQuick* imports on this engine
|
||||
QQmlEngine e2;
|
||||
QQmlComponent c2(&e2, settingsUrl);
|
||||
m_conf.reset(qobject_cast<Config *>(c2.create()));
|
||||
|
||||
if (!m_conf) {
|
||||
qCritical() << "qml: Error loading configuration file: %s\n", qPrintable(c2.errorString());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlRuntime::listConfFiles()
|
||||
{
|
||||
const QDir confResourceDir(m_confResourcePath);
|
||||
qInfo() << "%s\n", qPrintable(QCoreApplication::translate("main", "Built-in configurations:"));
|
||||
for (const QFileInfo &fi : confResourceDir.entryInfoList(QDir::Files))
|
||||
qInfo() << " %s\n", qPrintable(fi.baseName());
|
||||
qInfo() << "%s\n", qPrintable(QCoreApplication::translate("main", "Other configurations:"));
|
||||
bool foundOther = false;
|
||||
const QStringList otherLocations = QStandardPaths::standardLocations(
|
||||
QStandardPaths::AppConfigLocation);
|
||||
for (const auto &confDirPath : otherLocations) {
|
||||
const QDir confDir(confDirPath);
|
||||
for (const QFileInfo &fi : confDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||
foundOther = true;
|
||||
if (m_verboseMode)
|
||||
qInfo() << " %s\n", qPrintable(fi.absoluteFilePath());
|
||||
else
|
||||
qInfo() << " %s\n", qPrintable(fi.baseName());
|
||||
}
|
||||
}
|
||||
if (!foundOther)
|
||||
qInfo() << " %s\n", qPrintable(QCoreApplication::translate("main", "none"));
|
||||
if (m_verboseMode) {
|
||||
qInfo() << "%s\n", qPrintable(QCoreApplication::translate("main", "Checked in:"));
|
||||
for (const auto &confDirPath : otherLocations)
|
||||
qInfo() << " %s\n", qPrintable(confDirPath);
|
||||
}
|
||||
}
|
30
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.h
Normal file
30
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../qmlbase.h"
|
||||
#include "qmlconfiguration.h"
|
||||
|
||||
class QmlRuntime : public QmlBase
|
||||
{
|
||||
using QmlBase::QmlBase;
|
||||
|
||||
private:
|
||||
void initCoreApp() override;
|
||||
void populateParser() override;
|
||||
void initQmlRunner() override;
|
||||
|
||||
void listConfFiles();
|
||||
void loadConf(const QString &override, bool quiet);
|
||||
|
||||
const QString m_iconResourcePath = QStringLiteral(":/qt-project.org/QmlRuntime/resources/qml-64.png");
|
||||
const QString m_confResourcePath = QStringLiteral(":/runner/runnerconf/qmlruntime/");
|
||||
|
||||
|
||||
QSharedPointer<Config> m_conf;
|
||||
bool m_verboseMode = false;
|
||||
bool m_quietMode = false;
|
||||
int m_exitTimerId = -1;
|
||||
};
|
||||
|
@@ -12,4 +12,9 @@
|
||||
<file>mockfiles/ToolBarButton.qml</file>
|
||||
<file>mockfiles/ToggleButton.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/runner">
|
||||
<file>runnerconf/qmlruntime/default.qml</file>
|
||||
<file>runnerconf/qmlruntime/content/resizeItemToWindow.qml</file>
|
||||
<file>runnerconf/qmlruntime/content/resizeWindowToItem.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick 2.0
|
||||
|
||||
Window {
|
||||
property Item containedObject: null
|
||||
property bool __resizeGuard: false
|
||||
onContainedObjectChanged: {
|
||||
if (containedObject == undefined || containedObject == null) {
|
||||
visible = false
|
||||
return
|
||||
}
|
||||
__resizeGuard = true
|
||||
width = containedObject.width
|
||||
height = containedObject.height
|
||||
containedObject.parent = contentItem
|
||||
visible = true
|
||||
__resizeGuard = false
|
||||
}
|
||||
onWidthChanged: if (!__resizeGuard && containedObject)
|
||||
containedObject.width = width
|
||||
onHeightChanged: if (!__resizeGuard && containedObject)
|
||||
containedObject.height = height
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick 2.0
|
||||
|
||||
Window {
|
||||
property Item containedObject: null
|
||||
onContainedObjectChanged: {
|
||||
if (containedObject == undefined || containedObject == null) {
|
||||
visible = false
|
||||
return
|
||||
}
|
||||
width = Qt.binding(function () {
|
||||
return containedObject.width
|
||||
})
|
||||
height = Qt.binding(function () {
|
||||
return containedObject.height
|
||||
})
|
||||
containedObject.parent = contentItem
|
||||
visible = true
|
||||
}
|
||||
}
|
10
src/tools/qml2puppet/runnerconf/qmlruntime/default.qml
Normal file
10
src/tools/qml2puppet/runnerconf/qmlruntime/default.qml
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
import QmlRuntime.QmlConfiguration 1.0
|
||||
|
||||
Configuration {
|
||||
PartialScene {
|
||||
itemType: "QQuickItem"
|
||||
container: Qt.resolvedUrl("content/resizeItemToWindow.qml")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user