If there's e.g. an infinite loop during main() that would previously result in a blank page, but not error message. The expected case is that we would get a RangeError exception, but that exception never reaches the catch handlers in qtloader.js. Work around this by setting noInitialRun, followed by calling main manually. We then need to handle the case where the app.exec() workaround throws, which should not trigger an error. Pick-to: 6.7 Change-Id: Ia8431279308770981316cd168e4316341bfb2531 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
184 lines
4.7 KiB
C++
184 lines
4.7 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 stackOverflow()
|
|
{
|
|
stackOverflow(); // should eventually termniate with exception
|
|
}
|
|
|
|
void exitApp()
|
|
{
|
|
emscripten_force_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)
|
|
emscripten_force_exit(ExitValueImmediateReturn);
|
|
|
|
const bool crashImmediately =
|
|
std::find(arguments.begin(), arguments.end(), QStringLiteral("--crash-immediately"))
|
|
!= arguments.end();
|
|
if (crashImmediately)
|
|
crash();
|
|
|
|
const bool stackOverflowImmediately =
|
|
std::find(arguments.begin(), arguments.end(), QStringLiteral("--stack-owerflow-immediately"))
|
|
!= arguments.end();
|
|
if (stackOverflowImmediately)
|
|
stackOverflow();
|
|
|
|
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"
|