Add support for downloading files from the web server to the in-memory file system at application load time. See included documentation for usage. This preload functionality is different from Emscripten's --preload-file and --embed-file in that the files are not packed to a single data file or embedded in the JavaScript runtime. Instead, the files are downloaded individually from the web server, which means that they can be cached individually, and also updated individually without rebuilding the application. Any file type can be preloaded. The primary use case (at the moment) is preloading Qt plugins and QML imports. Pick-to: 6.6 Task-number: QTBUG-63925 Change-Id: I2b71b0d6a2c12ecd3ec58e319c679cd3f6b16631 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
172 lines
4.4 KiB
C++
172 lines
4.4 KiB
C++
// Copyright (C) 2023 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
#include <QtWidgets/QtWidgets>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
|
|
#include <emscripten/bind.h>
|
|
#include <emscripten/val.h>
|
|
#include <emscripten.h>
|
|
|
|
#include <QtGui/qpa/qplatformscreen.h>
|
|
|
|
namespace {
|
|
constexpr int ExitValueImmediateReturn = 42;
|
|
constexpr int ExitValueFromExitApp = 22;
|
|
|
|
std::string screenInformation()
|
|
{
|
|
auto screens = qGuiApp->screens();
|
|
std::ostringstream out;
|
|
out << "[";
|
|
const char *separator = "";
|
|
for (const auto &screen : screens) {
|
|
out << separator;
|
|
out << "[" << std::to_string(screen->geometry().x()) << ","
|
|
<< std::to_string(screen->geometry().y()) << ","
|
|
<< std::to_string(screen->geometry().width()) << ","
|
|
<< std::to_string(screen->geometry().height()) << "]";
|
|
separator = ",";
|
|
}
|
|
out << "]";
|
|
return out.str();
|
|
}
|
|
|
|
std::string logicalDpi()
|
|
{
|
|
auto screens = qGuiApp->screens();
|
|
std::ostringstream out;
|
|
out << "[";
|
|
const char *separator = "";
|
|
for (const auto &screen : screens) {
|
|
out << separator;
|
|
out << "[" << std::to_string(screen->handle()->logicalDpi().first) << ", "
|
|
<< std::to_string(screen->handle()->logicalDpi().second) << "]";
|
|
separator = ",";
|
|
}
|
|
out << "]";
|
|
return out.str();
|
|
}
|
|
|
|
std::string preloadedFiles()
|
|
{
|
|
QStringList files = QDir("/preload").entryList(QDir::Files);
|
|
std::ostringstream out;
|
|
out << "[";
|
|
const char *separator = "";
|
|
for (const auto &file : files) {
|
|
out << separator;
|
|
out << file.toStdString();
|
|
separator = ",";
|
|
}
|
|
out << "]";
|
|
return out.str();
|
|
}
|
|
|
|
void crash()
|
|
{
|
|
std::abort();
|
|
}
|
|
|
|
void exitApp()
|
|
{
|
|
exit(ExitValueFromExitApp);
|
|
}
|
|
|
|
void produceOutput()
|
|
{
|
|
fprintf(stdout, "Sample output!\n");
|
|
}
|
|
|
|
std::string retrieveArguments()
|
|
{
|
|
auto arguments = QApplication::arguments();
|
|
std::ostringstream out;
|
|
out << "[";
|
|
const char *separator = "";
|
|
for (const auto &argument : arguments) {
|
|
out << separator;
|
|
out << "'" << argument.toStdString() << "'";
|
|
separator = ",";
|
|
}
|
|
out << "]";
|
|
return out.str();
|
|
}
|
|
|
|
std::string getEnvironmentVariable(std::string name) {
|
|
return QString::fromLatin1(qgetenv(name.c_str())).toStdString();
|
|
}
|
|
} // namespace
|
|
|
|
class AppWindow : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
AppWindow() : m_layout(new QVBoxLayout(&m_ui))
|
|
{
|
|
addWidget<QLabel>("Qt Loader integration tests");
|
|
|
|
m_ui.setLayout(m_layout);
|
|
}
|
|
|
|
void show() { m_ui.show(); }
|
|
|
|
~AppWindow() = default;
|
|
|
|
private:
|
|
template<class T, class... Args>
|
|
T *addWidget(Args... args)
|
|
{
|
|
T *widget = new T(std::forward<Args>(args)..., &m_ui);
|
|
m_layout->addWidget(widget);
|
|
return widget;
|
|
}
|
|
|
|
QWidget m_ui;
|
|
QVBoxLayout *m_layout;
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
QApplication application(argc, argv);
|
|
const auto arguments = application.arguments();
|
|
const bool exitImmediately =
|
|
std::find(arguments.begin(), arguments.end(), QStringLiteral("--exit-immediately"))
|
|
!= arguments.end();
|
|
if (exitImmediately)
|
|
return ExitValueImmediateReturn;
|
|
|
|
const bool crashImmediately =
|
|
std::find(arguments.begin(), arguments.end(), QStringLiteral("--crash-immediately"))
|
|
!= arguments.end();
|
|
if (crashImmediately)
|
|
crash();
|
|
|
|
const bool noGui = std::find(arguments.begin(), arguments.end(), QStringLiteral("--no-gui"))
|
|
!= arguments.end();
|
|
if (!noGui) {
|
|
AppWindow window;
|
|
window.show();
|
|
return application.exec();
|
|
}
|
|
return application.exec();
|
|
}
|
|
|
|
EMSCRIPTEN_BINDINGS(qtLoaderIntegrationTest)
|
|
{
|
|
emscripten::constant("EXIT_VALUE_IMMEDIATE_RETURN", ExitValueImmediateReturn);
|
|
emscripten::constant("EXIT_VALUE_FROM_EXIT_APP", ExitValueFromExitApp);
|
|
|
|
emscripten::function("screenInformation", &screenInformation);
|
|
emscripten::function("logicalDpi", &logicalDpi);
|
|
emscripten::function("preloadedFiles", &preloadedFiles);
|
|
emscripten::function("crash", &crash);
|
|
emscripten::function("exitApp", &exitApp);
|
|
emscripten::function("produceOutput", &produceOutput);
|
|
emscripten::function("retrieveArguments", &retrieveArguments);
|
|
emscripten::function("getEnvironmentVariable", &getEnvironmentVariable);
|
|
}
|
|
|
|
#include "main.moc"
|