a4d1c30a1b
onExit is called whenever the application exits, i.e. when the app canvas should no longer be displayed and the loader/embedder code should take some action. Emscripten provides two callbacks which can be used here: - onExit, called when the app exits (but see EXIT_RUNTIME) - onAbort, called on abort errors. These map to the two cases Qt's onExit supports. onExit is not called when EXIT_RUNTIME is disabled, which means we don't need the special case for exit code 0. In addition call onExit on any exception. The second call to showUi() in html_shell.html is then not needed any more and we avoid duplicating the UI state handling in user code. Update the qtloader_integration test to handle changes in behavior (we no longer set the error text on exit). Use emscripten_force_exit() to simulate application exit - using this function makes Emscripten call onExit even when EXIT_RUNTIME is disabled. Pick-to: 6.6 Change-Id: I72b5463c1836e8d5054e594abbd304fbc67032b7 Reviewed-by: Piotr Wierciński <piotr.wiercinski@qt.io> Reviewed-by: Mikołaj Boc <Mikolaj.Boc@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()
|
|
{
|
|
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 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"
|