// Copyright (C) 2025 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace emscripten; static std::string toJSArray(const std::vector &elements) { std::ostringstream out; out << "["; bool comma = false; for (const auto &element : elements) { out << (comma ? "," : ""); out << element; comma = true; } out << "]"; return out.str(); } static std::string toJSString(const QString &qstring) { Q_ASSERT_X(([qstring]() { static QRegularExpression unescapedQuoteRegex(R"re((?:^|[^\\])')re"); return qstring.indexOf(unescapedQuoteRegex) == -1; })(), Q_FUNC_INFO, "Unescaped single quotes found"); return "'" + qstring.toStdString() + "'"; } static std::string rectToJSObject(const QRect &rect) { std::ostringstream out; out << "{" << " x: " << std::to_string(rect.x()) << "," << " y: " << std::to_string(rect.y()) << "," << " width: " << std::to_string(rect.width()) << "," << " height: " << std::to_string(rect.height()) << "}"; return out.str(); } static std::string screenToJSObject(const QScreen &screen) { std::ostringstream out; out << "{" << " name: " << toJSString(screen.name()) << "," << " geometry: " << rectToJSObject(screen.geometry()) << "}"; return out.str(); } static std::string windowToJSObject(const QWindow &window) { std::ostringstream out; out << "{" << " id: " << std::to_string(window.winId()) << "," << " geometry: " << rectToJSObject(window.geometry()) << "," << " frameGeometry: " << rectToJSObject(window.frameGeometry()) << "," << " screen: " << screenToJSObject(*window.screen()) << "," << " title: '" << window.title().toStdString() << "' }"; return out.str(); } static void windowInformation() { auto windows = qGuiApp->allWindows(); std::vector windowsAsJsObjects; windowsAsJsObjects.reserve(windows.size()); std::transform(windows.begin(), windows.end(), std::back_inserter(windowsAsJsObjects), [](const QWindow *window) { return windowToJSObject(*window); }); emscripten::val::global("window").call("windowInformationCallback", emscripten::val(toJSArray(windowsAsJsObjects))); } static void screenInformation() { auto screens = qGuiApp->screens(); std::vector screensAsJsObjects; screensAsJsObjects.reserve(screens.size()); std::transform(screens.begin(), screens.end(), std::back_inserter(screensAsJsObjects), [](const QScreen *screen) { return screenToJSObject(*screen); }); emscripten::val::global("window").call("screenInformationCallback", emscripten::val(toJSArray(screensAsJsObjects))); } QWindow *qmlParentWindow = nullptr; static void run_QML(const std::string &qmlfile) { QScreen *parentScreen = nullptr; { auto screens = qGuiApp->screens(); if (screens.length() > 0) parentScreen = screens[0]; else { qWarning() << "No parent screen"; return; } } qmlParentWindow = new QWindow(parentScreen); qmlParentWindow->setFlag(Qt::WindowTitleHint); qmlParentWindow->setFlag(Qt::WindowMaximizeButtonHint); qmlParentWindow->setTitle("title"); qmlParentWindow->setGeometry(0, 0, 800, 800); qmlParentWindow->setScreen(parentScreen); qmlParentWindow->setVisible(true); auto view = new QQuickView(qmlParentWindow); view->setSource(QUrl(QString::fromUtf8(("qrc:/" + qmlfile).c_str()))); view->show(); } static void kill_QML() { qmlParentWindow->deleteLater(); qmlParentWindow = NULL; } #if QT_CONFIG(wasm_jspi) # define EMSC_BIND_FUNC(name, afunction) \ emscripten::function(name, afunction, emscripten::async()) #else # define EMSC_BIND_FUNC(name, afunction) \ emscripten::function(name, afunction) #endif EMSCRIPTEN_BINDINGS(qwasmwindow) { EMSC_BIND_FUNC("screenInformation", &screenInformation); EMSC_BIND_FUNC("windowInformation", &windowInformation); EMSC_BIND_FUNC("run_QML", &run_QML); EMSC_BIND_FUNC("kill_QML", &kill_QML); } int main(int argc, char **argv) { qputenv("QT_WASM_ENABLE_ACCESSIBILITY", "1"); QGuiApplication app(argc, argv); app.exec(); return 0; }