Morten Sørvig a9bbcdd7bf wasm: support foreign windows
Add support for embedding native html elements using
QWindow::fromWinId().

WId is an emscripten::val *, e.g. a pointer to val which
holds a html element. The element can be created either from
C++ using emscripten::val, or from JavaScript. User code
owns the val * as usual for WId; ownership is not passed to the
QWindow instance.

Set QWasmWindow::m_window to be the native element when
fromWinId() is used, and skip the rest of the QWasmWindow
implementation in that case: We don't need to install event
handlers or provide accessibility elements.

Make key and pointer event handlers stop propagation only
if the event was not accepted. This makes sure that input
events reach the embedded native element.

Limit setPointerCapture calls to when the event is targeted
for Qt elements only. Determining the true target can be
a bit tricky when shadow DOM is in use since the browsers
may retarget the event. Use composedPath() to get the true
event target.

Task-number: QTBUG-128804
Task-number: QTBUG-128732
Change-Id: I5ce66e93bacb06abfd042916687cd45fc9588c51
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
2025-01-29 13:59:09 +01:00

93 lines
2.7 KiB
C++

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtWidgets>
#include <emscripten.h>
#include <emscripten/val.h>
using emscripten::val;
using emscripten::EM_VAL;
val createInputElemet(std::string subtype)
{
val document = val::global("document");
val input = document.call<val>("createElement", std::string("input"));
input.set("type", subtype);
return input;
}
EM_JS(EM_VAL, createCalendar, (), {
var calendar = document.createElement("calendar-date");
calendar.innerHTML = "<calendar-month></calendar-month>";
return Emval.toHandle(calendar);
});
val createCallyElemet()
{
static bool initializedCalendarComponent = []{
return EM_ASM_INT(
console.log("Loading calendar module");
var script = document.createElement('script');
script.src = "https://unpkg.com/cally";
script.type = "module";
document.head.appendChild(script);
console.log(script);
return true;
);
}();
Q_ASSERT(initializedCalendarComponent);
return val::take_ownership(createCalendar());
}
class ForeginWindowContainer : public QWidget
{
Q_OBJECT
public:
ForeginWindowContainer() {
QCheckBox *test = new QCheckBox("Qt CheckBox");
test->setGeometry(20, 20, 150, 20);
test->setParent(this);
m_calendarInput = std::make_unique<val>(createInputElemet("date"));
m_colorPickerInput = std::make_unique<val>(createInputElemet("color"));
QWindow *calendarWindow = QWindow::fromWinId(WId(m_calendarInput.get()));
QWindow *colorPickerWindow = QWindow::fromWinId(WId(m_colorPickerInput.get()));
QWidget *calendarContainer = QWidget::createWindowContainer(calendarWindow, this);
calendarContainer->setGeometry(20, 50, 300, 40);
QWidget *colorPickerContainer = QWidget::createWindowContainer(colorPickerWindow, this);
colorPickerContainer->setGeometry(20, 90, 300, 40);
val callyCalendarElement = createCallyElemet();
QWindow *callyWindow =QWindow::fromWinId(WId(new val(callyCalendarElement)));
QWidget *callyContainer = QWidget::createWindowContainer(callyWindow, this);
callyContainer->setGeometry(20, 130, 300, 400);
}
~ForeginWindowContainer() {
}
private:
std::unique_ptr<val> m_calendarInput;
std::unique_ptr<val> m_colorPickerInput;
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QGuiApplication::styleHints()->setColorScheme(Qt::ColorScheme::Light);
ForeginWindowContainer container;
container.showNormal();
return app.exec();
}
#include "main.moc"