summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/wasm
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@qt.io>2019-02-15 22:04:09 +0100
committerMorten Johan Sørvig <morten.sorvig@qt.io>2019-03-08 10:09:57 +0000
commitcaa74f16d41ebe65e1edbea219f799cf246d6067 (patch)
tree5e7798bdfc20575e99ecce2fb8066d8aef63cfb8 /src/plugins/platforms/wasm
parent452c644c5c51d78d72dde703c81fc7789e5b84f1 (diff)
wasm: support rendering to multiple canvases
Qt (via the the qtloader.js API) now supports rendering to multiple canvases. The application sees each canvas as a QScreen. Make qtloader.js support multiple canvases: var qtloader = QtLoader({ canvasElements : [array-of-canvas], showCanvas: function() { // make canvas(es) visible }, }); The canvases were previously created/returned by showCanvas(), however this function is called after the Qt app has been started and adding screens that that point is too late. (This worked before since there was only one screen, and no need to connect each screen instance to specific canvas.) Remove QWasmScreen, QWasmCompositor, and QWasmEventTranslator singletons from QWasmIntegration. These are are now crated per-screen and are owned by the QWasmScreen. Task-number: QTBUG-64079 Change-Id: I24689929fd5bfb7ff0ba076f66937728fa4bc4e4 Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
Diffstat (limited to 'src/plugins/platforms/wasm')
-rw-r--r--src/plugins/platforms/wasm/qtloader.js55
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.cpp53
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp25
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h7
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.cpp16
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp38
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.h6
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp56
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h11
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp4
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp69
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h25
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html14
14 files changed, 224 insertions, 156 deletions
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index 203213db56..049eb1c35e 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -50,6 +50,7 @@
// External mode.usage:
//
// var config = {
+// canvasElements : [$("canvas-id")],
// showLoader: function() {
// loader.style.display = 'block'
// canvas.style.display = 'hidden'
@@ -69,6 +70,8 @@
// One or more HTML elements. QtLoader will display loader elements
// on these while loading the applicaton, and replace the loader with a
// canvas on load complete.
+// canvasElements : [canvas-element, ...]
+// One or more canvas elements.
// showLoader : function(status, containerElement)
// Optional loading element constructor function. Implement to create
// a custom loading screen. This function may be called multiple times,
@@ -146,8 +149,25 @@ function QtLoader(config)
while (element.firstChild) element.removeChild(element.firstChild);
}
- // Set default state handler functions if needed
+ function createCanvas() {
+ var canvas = document.createElement("canvas");
+ canvas.className = "QtCanvas";
+ canvas.style.height = "100%";
+ canvas.style.width = "100%";
+
+ // Set contentEditable in order to enable clipboard events; hide the resulting focus frame.
+ canvas.contentEditable = true;
+ canvas.style.outline = "0px solid transparent";
+ canvas.style.cursor = "default";
+
+ return canvas;
+ }
+
+ // Set default state handler functions and create canvases if needed
if (config.containerElements !== undefined) {
+
+ config.canvasElements = config.containerElements.map(createCanvas);
+
config.showError = config.showError || function(errorText, container) {
removeChildren(container);
var errorTextElement = document.createElement("text");
@@ -164,19 +184,8 @@ function QtLoader(config)
return loadingText;
};
- config.showCanvas = config.showCanvas || function(container) {
+ config.showCanvas = config.showCanvas || function(canvas, container) {
removeChildren(container);
- var canvas = document.createElement("canvas");
- canvas.className = "QtCanvas"
- canvas.style.height = "100%"
- canvas.style.width = "100%"
-
- // Set contentEditable in order to enable clipboard events; hide the resulting focus frame.
- canvas.contentEditable = true;
- canvas.style.outline = "0px solid transparent";
- canvas.style.cursor = "default";
-
- return canvas;
}
config.showExit = config.showExit || function(crashed, exitCode, container) {
@@ -391,6 +400,8 @@ function QtLoader(config)
Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'});
+ Module.qtCanvasElements = config.canvasElements;
+
config.restart = function() {
// Restart by reloading the page. This will wipe all state which means
@@ -445,19 +456,17 @@ function QtLoader(config)
}
function setCanvasContent() {
- var firstCanvas;
if (config.containerElements === undefined) {
- firstCanvas = config.showCanvas();
- } else {
- for (container of config.containerElements) {
- var canvasElement = config.showCanvas(container);
- container.appendChild(canvasElement);
- }
- firstCanvas = config.containerElements[0].firstChild;
+ if (config.showCanvas !== undefined)
+ config.showCanvas();
+ return;
}
- if (Module.canvas === undefined) {
- Module.canvas = firstCanvas;
+ for (var i = 0; i < config.containerElements.length; ++i) {
+ var container = config.containerElements[i];
+ var canvas = config.canvasElements[i];
+ config.showCanvas(canvas, container);
+ container.appendChild(canvas);
}
}
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp
index 63fea7738d..7a7b253b19 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.cpp
+++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp
@@ -123,9 +123,11 @@ EMSCRIPTEN_BINDINGS(clipboard_module) {
function("qClipboardPasteTo", &qClipboardPasteTo);
}
-QWasmClipboard::QWasmClipboard() :
- hasClipboardApi(false)
+QWasmClipboard::QWasmClipboard()
{
+ val clipboard = val::global("navigator")["clipboard"];
+ hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined());
+
initClipboardEvents();
}
@@ -177,29 +179,32 @@ void QWasmClipboard::qWasmClipboardPaste(QMimeData *mData)
void QWasmClipboard::initClipboardEvents()
{
- val navigator = val::global("navigator");
- val permissions = navigator["permissions"];
- val clipboard = navigator["clipboard"];
+ if (!hasClipboardApi)
+ return;
- hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined());
- if (hasClipboardApi) {
- val readPermissionsMap = val::object();
- readPermissionsMap.set("name", val("clipboard-read"));
- permissions.call<val>("query", readPermissionsMap);
-
- val writePermissionsMap = val::object();
- writePermissionsMap.set("name", val("clipboard-write"));
- permissions.call<val>("query", writePermissionsMap);
-
- } else {
- val canvas = val::module_property("canvas");
- canvas.call<void>("addEventListener", std::string("cut"),
- val::module_property("qClipboardCutTo"));
- canvas.call<void>("addEventListener", std::string("copy"),
- val::module_property("qClipboardCopyTo"));
- canvas.call<void>("addEventListener", std::string("paste"),
- val::module_property("qClipboardPasteTo"));
- }
+ val permissions = val::global("navigator")["permissions"];
+ val readPermissionsMap = val::object();
+ readPermissionsMap.set("name", val("clipboard-read"));
+ permissions.call<val>("query", readPermissionsMap);
+
+ val writePermissionsMap = val::object();
+ writePermissionsMap.set("name", val("clipboard-write"));
+ permissions.call<val>("query", writePermissionsMap);
+}
+
+void QWasmClipboard::installEventHandlers(const QString &canvasId)
+{
+ if (hasClipboardApi)
+ return;
+
+ // Fallback path for browsers which do not support direct clipboard access
+ val canvas = val::global(canvasId.toUtf8().constData());
+ canvas.call<void>("addEventListener", std::string("cut"),
+ val::module_property("qClipboardCutTo"));
+ canvas.call<void>("addEventListener", std::string("copy"),
+ val::module_property("qClipboardCopyTo"));
+ canvas.call<void>("addEventListener", std::string("paste"),
+ val::module_property("qClipboardPasteTo"));
}
void QWasmClipboard::readTextFromClipboard()
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h
index e64b2e5007..00aae8fead 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.h
+++ b/src/plugins/platforms/wasm/qwasmclipboard.h
@@ -51,6 +51,7 @@ public:
static void qWasmClipboardPaste(QMimeData *mData);
void initClipboardEvents();
+ void installEventHandlers(const QString &canvasId);
bool hasClipboardApi;
void readTextFromClipboard();
void writeTextToClipboard();
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index 3dc6b7d2f3..90cc20789d 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -56,8 +56,9 @@ QWasmCompositedWindow::QWasmCompositedWindow()
{
}
-QWasmCompositor::QWasmCompositor()
- : m_frameBuffer(nullptr)
+QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
+ :QObject(screen)
+ , m_frameBuffer(nullptr)
, m_blitter(new QOpenGLTextureBlitter)
, m_needComposit(false)
, m_inFlush(false)
@@ -107,11 +108,6 @@ void QWasmCompositor::removeWindow(QWasmWindow *window)
notifyTopWindowChanged(window);
}
-void QWasmCompositor::setScreen(QWasmScreen *screen)
-{
- m_screen = screen;
-}
-
void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
{
QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
@@ -654,7 +650,7 @@ void QWasmCompositor::frame()
m_needComposit = false;
- if (m_windowStack.empty() || !m_screen)
+ if (m_windowStack.empty() || !screen())
return;
QWasmWindow *someWindow = nullptr;
@@ -673,7 +669,7 @@ void QWasmCompositor::frame()
if (m_context.isNull()) {
m_context.reset(new QOpenGLContext());
//mContext->setFormat(mScreen->format());
- m_context->setScreen(m_screen->screen());
+ m_context->setScreen(screen()->screen());
m_context->create();
}
@@ -682,8 +678,8 @@ void QWasmCompositor::frame()
if (!m_blitter->isCreated())
m_blitter->create();
- qreal dpr = m_screen->devicePixelRatio();
- glViewport(0, 0, m_screen->geometry().width() * dpr, m_screen->geometry().height() * dpr);
+ qreal dpr = screen()->devicePixelRatio();
+ glViewport(0, 0, screen()->geometry().width() * dpr, screen()->geometry().height() * dpr);
m_context->functions()->glClearColor(0.2, 0.2, 0.2, 1.0);
m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@@ -697,7 +693,7 @@ void QWasmCompositor::frame()
if (!compositedWindow.visible)
continue;
- drawWindow(m_blitter.data(), m_screen, window);
+ drawWindow(m_blitter.data(), screen(), window);
}
m_blitter->release();
@@ -719,3 +715,8 @@ void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
requestRedraw();
QWindowSystemInterface::handleWindowActivated(window->window());
}
+
+QWasmScreen *QWasmCompositor::screen()
+{
+ return static_cast<QWasmScreen *>(parent());
+}
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
index 4e5ed46cec..ed6facdcc3 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.h
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -62,7 +62,7 @@ class QWasmCompositor : public QObject
{
Q_OBJECT
public:
- QWasmCompositor();
+ QWasmCompositor(QWasmScreen *screen);
~QWasmCompositor();
enum QWasmSubControl {
@@ -103,7 +103,6 @@ public:
void addWindow(QWasmWindow *window, QWasmWindow *parentWindow = nullptr);
void removeWindow(QWasmWindow *window);
- void setScreen(QWasmScreen *screen);
void setVisible(QWasmWindow *window, bool visible);
void raise(QWasmWindow *window);
@@ -129,8 +128,7 @@ private slots:
void frame();
private:
- void createFrameBuffer();
- void flushCompletedCallback(int32_t);
+ QWasmScreen *screen();
void notifyTopWindowChanged(QWasmWindow *window);
void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
@@ -142,7 +140,6 @@ private:
QImage *m_frameBuffer;
QScopedPointer<QOpenGLContext> m_context;
QScopedPointer<QOpenGLTextureBlitter> m_blitter;
- QWasmScreen *m_screen;
QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows;
QList<QWasmWindow *> m_windowStack;
diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp
index 744b160dd1..2b3f37300d 100644
--- a/src/plugins/platforms/wasm/qwasmcursor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcursor.cpp
@@ -28,20 +28,21 @@
****************************************************************************/
#include "qwasmcursor.h"
+#include "qwasmscreen.h"
#include <QtCore/qdebug.h>
+#include <QtGui/qwindow.h>
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
- if (windowCursor == nullptr)
+ if (!windowCursor || !window)
+ return;
+ QScreen *screen = window->screen();
+ if (!screen)
return;
-
- // FIXME: The HTML5 plugin sets the cursor on the native canvas; when using multiple windows
- // multiple cursors need to be managed taking mouse postion and stacking into account.
- Q_UNUSED(window);
// Bitmap and custom cursors are not implemented (will fall back to "auto")
if (windowCursor->shape() == Qt::BitmapCursor || windowCursor->shape() >= Qt::CustomCursor)
@@ -52,8 +53,9 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
if (htmlCursorName.isEmpty())
htmlCursorName = "auto";
- // Set cursor on the main canvas
- emscripten::val canvasStyle = emscripten::val::module_property("canvas")["style"];
+ // Set cursor on the canvas
+ QString canvasId = QWasmScreen::get(screen)->canvasId();
+ emscripten::val canvasStyle = emscripten::val::global(canvasId.toUtf8().constData())["style"];
canvasStyle.set("cursor", emscripten::val(htmlCursorName.constData()));
}
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
index 23bf9a7de6..14222da807 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -320,8 +320,8 @@ EMSCRIPTEN_BINDINGS(mouse_module) {
function("mouseWheelEvent", &mouseWheelEvent);
}
-QWasmEventTranslator::QWasmEventTranslator(QObject *parent)
- : QObject(parent)
+QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen)
+ : QObject(screen)
, draggedWindow(nullptr)
, lastWindow(nullptr)
, pressedButtons(Qt::NoButton)
@@ -332,13 +332,16 @@ QWasmEventTranslator::QWasmEventTranslator(QObject *parent)
touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition);
QWindowSystemInterface::registerTouchDevice(touchDevice);
- QWasmScreen *wasmScreen = QWasmIntegration::get()->screen();
- initEventHandlers(wasmScreen->m_canvasId);
+ initEventHandlers();
}
-void QWasmEventTranslator::initEventHandlers(const QString &canvas)
+void QWasmEventTranslator::initEventHandlers()
{
- const char *canvasId = canvas.toLocal8Bit().constData();
+ qDebug() << "QWasmEventTranslator::initEventHandlers";
+
+ QByteArray _canvasId = screen()->canvasId().toUtf8();
+ const char *canvasId = _canvasId.constData();
+
// The Platform Detect: expand coverage and move as needed
enum Platform {
GenericPlatform,
@@ -375,7 +378,7 @@ void QWasmEventTranslator::initEventHandlers(const QString &canvas)
emscripten_set_touchmove_callback(canvasId, (void *)this, 1, &touchCallback);
emscripten_set_touchcancel_callback(canvasId, (void *)this, 1, &touchCallback);
- emscripten_set_resize_callback(canvasId, (void *)this, 1, uiEvent_cb);
+ emscripten_set_resize_callback(nullptr, (void *)this, 1, uiEvent_cb); // Note: handles browser window resize
}
@@ -425,6 +428,11 @@ int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEve
return accepted ? 1 : 0;
}
+QWasmScreen *QWasmEventTranslator::screen()
+{
+ return static_cast<QWasmScreen *>(parent());
+}
+
Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey)
{
Qt::Key qtKey = Qt::Key_unknown;
@@ -541,14 +549,14 @@ void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode,
void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
{
auto timestamp = mouseEvent->timestamp;
- QPoint point(mouseEvent->canvasX, mouseEvent->canvasY);
+ QPoint point(mouseEvent->targetX, mouseEvent->targetY);
QEvent::Type buttonEventType = QEvent::None;
Qt::MouseButton button = translateMouseButton(mouseEvent->button);
Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent);
- QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
+ QWindow *window2 = screen()->compositor()->windowAt(point, 5);
if (window2 != nullptr)
lastWindow = window2;
@@ -645,6 +653,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
{
Q_UNUSED(eventType)
+ QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
EmscriptenMouseEvent mouseEvent = wheelEvent->mouse;
int scrollFactor = 0;
@@ -668,7 +677,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
auto timestamp = mouseEvent.timestamp;
QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY);
- QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(globalPoint, 5);
+ QWindow *window2 = eventTranslator->screen()->compositor()->windowAt(globalPoint, 5);
QPoint localPoint(globalPoint.x() - window2->geometry().x(), globalPoint.y() - window2->geometry().y());
@@ -686,6 +695,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
{
+ QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
QList<QWindowSystemInterface::TouchPoint> touchPointList;
touchPointList.reserve(touchEvent->numTouches);
QWindow *window2;
@@ -695,7 +705,7 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven
const EmscriptenTouchPoint *touches = &touchEvent->touches[i];
QPoint point(touches->canvasX, touches->canvasY);
- window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
+ window2 = eventTranslator->screen()->compositor()->windowAt(point, 5);
QWindowSystemInterface::TouchPoint touchPoint;
@@ -878,15 +888,13 @@ bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboa
int QWasmEventTranslator::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData)
{
Q_UNUSED(e)
- Q_UNUSED(userData)
+ QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
if (eventType == EMSCRIPTEN_EVENT_RESIZE) {
// This resize event is called when the HTML window is resized. Depending
// on the page layout the the canvas might also have been resized, so we
// update the Qt screen size (and canvas render size).
- QWasmScreen *wasmScreen = QWasmIntegration::get()->screen();
-
- wasmScreen->updateQScreenAndCanvasRenderSize(wasmScreen->m_canvasId.toLocal8Bit().constData());
+ eventTranslator->screen()->updateQScreenAndCanvasRenderSize();
}
return 0;
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h
index a9a00eab0b..ba08dce946 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.h
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h
@@ -48,7 +48,7 @@ class QWasmEventTranslator : public QObject
public:
- explicit QWasmEventTranslator(QObject *parent = 0);
+ explicit QWasmEventTranslator(QWasmScreen *screen);
static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
static int mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
@@ -60,12 +60,12 @@ public:
static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData);
void processEvents();
- void initEventHandlers(const QString &);
+ void initEventHandlers();
Q_SIGNALS:
void getWindowAt(const QPoint &point, QWindow **window);
private:
-
+ QWasmScreen *screen();
Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey);
template <typename Event>
QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index f45048ffa4..1964cefdad 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -70,36 +70,35 @@ QWasmIntegration *QWasmIntegration::s_instance;
QWasmIntegration::QWasmIntegration()
: m_fontDb(nullptr),
- m_compositor(new QWasmCompositor),
- m_screen(new QWasmScreen(m_compositor)),
m_eventDispatcher(nullptr),
m_clipboard(new QWasmClipboard)
{
-
- globalHtml5Integration = this;
s_instance = this;
- emscripten::val defaultCanvasId = emscripten::val::global("canvas");
- canvasIds.append(QString::fromStdString(defaultCanvasId["id"].as<std::string>()));
- m_screen->setCanvas(canvasIds.at(0));
-
- globalHtml5Integration = this;
-
- screen()->updateQScreenAndCanvasRenderSize(m_screen->m_canvasId);
- screenAdded(m_screen);
-
- m_eventTranslator = new QWasmEventTranslator;
+ // We expect that qtloader.js has populated Module.qtCanvasElements with one or more canvases.
+ // Also check Module.canvas, which may be set if the emscripen or a custom loader is used.
+ emscripten::val qtCanvaseElements = val::module_property("qtCanvasElements");
+ emscripten::val canvas = val::module_property("canvas");
+
+ if (!qtCanvaseElements.isUndefined()) {
+ int screenCount = qtCanvaseElements["length"].as<int>();
+ for (int i = 0; i < screenCount; ++i) {
+ emscripten::val canvas = qtCanvaseElements[i].as<emscripten::val>();
+ QString canvasId = QString::fromStdString(canvas["id"].as<std::string>());
+ addScreen(canvasId);
+ }
+ } else if (!canvas.isUndefined()){
+ QString canvasId = QString::fromStdString(canvas["id"].as<std::string>());
+ addScreen(canvasId);
+ }
emscripten::val::global("window").set("onbeforeunload", val::module_property("browserBeforeUnload"));
-
}
QWasmIntegration::~QWasmIntegration()
{
- delete m_compositor;
- destroyScreen(m_screen);
delete m_fontDb;
- delete m_eventTranslator;
+ qDeleteAll(m_screens);
s_instance = nullptr;
}
@@ -124,13 +123,15 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
{
- return new QWasmWindow(window, m_compositor, m_backingStores.value(window));
+ QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
+ return new QWasmWindow(window, compositor, m_backingStores.value(window));
}
QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
{
#ifndef QT_NO_OPENGL
- QWasmBackingStore *backingStore = new QWasmBackingStore(m_compositor, window);
+ QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
+ QWasmBackingStore *backingStore = new QWasmBackingStore(compositor, window);
m_backingStores.insert(window, backingStore);
return backingStore;
#else
@@ -177,9 +178,20 @@ QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const
QPlatformClipboard* QWasmIntegration::clipboard() const
{
- if (!m_clipboard)
- m_clipboard = new QWasmClipboard;
return m_clipboard;
}
+QVector<QWasmScreen *> QWasmIntegration::screens()
+{
+ return m_screens;
+}
+
+void QWasmIntegration::addScreen(const QString &canvasId)
+{
+ QWasmScreen *screen = new QWasmScreen(canvasId);
+ m_clipboard->installEventHandlers(canvasId);
+ m_screens.append(screen);
+ screenAdded(screen);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index 0b73303bf4..5c0ac0b297 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -71,23 +71,20 @@ public:
QPlatformTheme *createPlatformTheme(const QString &name) const override;
QPlatformClipboard *clipboard() const override;
- QWasmScreen *screen() { return m_screen; }
- QWasmCompositor *compositor() { return m_compositor; }
- QWasmEventTranslator *eventTranslator() { return m_eventTranslator; }
+ QVector<QWasmScreen *>screens();
QWasmClipboard *getWasmClipboard() { return m_clipboard; }
static QWasmIntegration *get() { return s_instance; }
static void QWasmBrowserExit();
- QStringList canvasIds;
private:
+ void addScreen(const QString &canvasId);
+
mutable QWasmFontDatabase *m_fontDb;
- QWasmCompositor *m_compositor;
- mutable QWasmScreen *m_screen;
- mutable QWasmEventTranslator *m_eventTranslator;
mutable QWasmEventDispatcher *m_eventDispatcher;
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
+ QVector<QWasmScreen *> m_screens;
mutable QWasmClipboard *m_clipboard;
static QWasmIntegration *s_instance;
};
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
index e71da0c217..ae43e2ebf0 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -57,9 +57,7 @@ void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surfac
emscripten_webgl_destroy_context(m_context);
// Create new context
- QWasmScreen *wasmScreen = QWasmIntegration::get()->screen();
- const QString canvasId = wasmScreen->m_canvasId;
- // FIXME: get the actual canvas from the surface.
+ const QString canvasId = QWasmScreen::get(surface->screen())->canvasId();
m_context = createEmscriptenContext(canvasId, m_requestedFormat);
// Register context-lost callback.
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index fb14803ff8..a26cafa900 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -29,8 +29,10 @@
#include "qwasmscreen.h"
#include "qwasmwindow.h"
+#include "qwasmeventtranslator.h"
#include "qwasmcompositor.h"
#include <emscripten/bind.h>
+#include <emscripten/val.h>
#include <QtEglSupport/private/qeglconvenience_p.h>
#ifndef QT_NO_OPENGL
@@ -44,12 +46,13 @@
QT_BEGIN_NAMESPACE
-QWasmScreen::QWasmScreen(QWasmCompositor *compositor)
- : m_compositor(compositor)
- , m_depth(32)
- , m_format(QImage::Format_RGB32)
+QWasmScreen::QWasmScreen(const QString &canvasId)
+ : m_canvasId(canvasId)
+
{
- m_compositor->setScreen(this);
+ m_compositor = new QWasmCompositor(this);
+ m_eventTranslator = new QWasmEventTranslator(this);
+ updateQScreenAndCanvasRenderSize();
}
QWasmScreen::~QWasmScreen()
@@ -57,6 +60,31 @@ QWasmScreen::~QWasmScreen()
}
+QWasmScreen *QWasmScreen::get(QPlatformScreen *screen)
+{
+ return static_cast<QWasmScreen *>(screen);
+}
+
+QWasmScreen *QWasmScreen::get(QScreen *screen)
+{
+ return get(screen->handle());
+}
+
+QWasmCompositor *QWasmScreen::compositor()
+{
+ return m_compositor;
+}
+
+QWasmEventTranslator *QWasmScreen::eventTranslator()
+{
+ return m_eventTranslator;
+}
+
+QString QWasmScreen::canvasId() const
+{
+ return m_canvasId;
+}
+
QRect QWasmScreen::geometry() const
{
return m_geometry;
@@ -82,6 +110,11 @@ qreal QWasmScreen::devicePixelRatio() const
return qreal(htmlWindowDpr);
}
+QString QWasmScreen::name() const
+{
+ return m_canvasId;
+}
+
QPlatformCursor *QWasmScreen::cursor() const
{
return const_cast<QWasmCursor *>(&m_cursor);
@@ -114,14 +147,7 @@ void QWasmScreen::setGeometry(const QRect &rect)
resizeMaximizedWindows();
}
-static void set_canvas_size(double width, double height, const char *canvasId)
-{
- emscripten::val canvas = emscripten::val::global(canvasId);
- canvas.set("width", width);
- canvas.set("height", height);
-}
-
-void QWasmScreen::updateQScreenAndCanvasRenderSize(const QString &canvasId)
+void QWasmScreen::updateQScreenAndCanvasRenderSize()
{
// The HTML canvas has two sizes: the CSS size and the canvas render size.
// The CSS size is determined according to standard CSS rules, while the
@@ -130,17 +156,22 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize(const QString &canvasId)
// Setting the render size to a value larger than the CSS size enables high-dpi
// rendering.
+ QByteArray canvasId = m_canvasId.toUtf8();
double css_width;
double css_height;
- emscripten_get_element_css_size(canvasId.toLocal8Bit().constData(), &css_width, &css_height);
+ emscripten_get_element_css_size(canvasId.constData(), &css_width, &css_height);
QSizeF cssSize(css_width, css_height);
- QWasmScreen *screen = QWasmIntegration::get()->screen();
- QSizeF canvasSize = cssSize * screen->devicePixelRatio();
+ QSizeF canvasSize = cssSize * devicePixelRatio();
+ emscripten::val canvas = emscripten::val::global(canvasId.constData());
+ canvas.set("width", canvasSize.width());
+ canvas.set("height", canvasSize.height());
+
+ emscripten::val rect = canvas.call<emscripten::val>("getBoundingClientRect");
+ QPoint position(rect["left"].as<int>(), rect["top"].as<int>());
- set_canvas_size(canvasSize.width(), canvasSize.height(), canvasId.toLocal8Bit().constData());
- screen->setGeometry(QRect(QPoint(0, 0), cssSize.toSize()));
- QWasmIntegration::get()->compositor()->redrawWindowContent();
+ setGeometry(QRect(position, cssSize.toSize()));
+ m_compositor->redrawWindowContent();
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
index d5080835c9..82d2a83edb 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -43,20 +43,28 @@ class QPlatformOpenGLContext;
class QWasmWindow;
class QWasmBackingStore;
class QWasmCompositor;
+class QWasmEventTranslator;
class QOpenGLContext;
class QWasmScreen : public QObject, public QPlatformScreen
{
Q_OBJECT
public:
-
- QWasmScreen(QWasmCompositor *compositor);
+ QWasmScreen(const QString &canvasId);
~QWasmScreen();
+ static QWasmScreen *get(QPlatformScreen *screen);
+ static QWasmScreen *get(QScreen *screen);
+ QString canvasId() const;
+
+ QWasmCompositor *compositor();
+ QWasmEventTranslator *eventTranslator();
+
QRect geometry() const override;
int depth() const override;
QImage::Format format() const override;
qreal devicePixelRatio() const override;
+ QString name() const override;
QPlatformCursor *cursor() const override;
void resizeMaximizedWindows();
@@ -64,19 +72,18 @@ public:
QWindow *topLevelAt(const QPoint &p) const override;
void invalidateSize();
- static void updateQScreenAndCanvasRenderSize(const QString &);
- QString m_canvasId;
- void setCanvas(const QString &canvasId) { m_canvasId = canvasId; }
+ void updateQScreenAndCanvasRenderSize();
public slots:
void setGeometry(const QRect &rect);
private:
- QWasmCompositor *m_compositor;
-
+ QString m_canvasId;
+ QWasmCompositor *m_compositor = nullptr;
+ QWasmEventTranslator *m_eventTranslator = nullptr;
QRect m_geometry = QRect(0, 0, 100, 100);
- int m_depth;
- QImage::Format m_format;
+ int m_depth = 32;
+ QImage::Format m_format = QImage::Format_RGB32;
QWasmCursor m_cursor;
};
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index 110d45e036..39bb711b6b 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -15,23 +15,24 @@
</style>
</head>
<body onload="init()">
- <figure style="overflow:visible;" id="spinner">
+ <figure style="overflow:visible;" id="qtspinner">
<center style="margin-top:1.5em; line-height:150%">
<img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img>
<strong>Qt for WebAssembly: APPNAME</strong>
- <div id="status"></div>
+ <div id="qtstatus"></div>
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
</center>
</figure>
- <canvas id="canvas" oncontextmenu="event.preventDefault()" contenteditable="true"></canvas>
+ <canvas id="qtcanvas" oncontextmenu="event.preventDefault()" contenteditable="true"></canvas>
<script type='text/javascript'>
function init() {
- var spinner = document.getElementById('spinner');
- var canvas = document.getElementById('canvas');
- var status = document.getElementById('status')
+ var spinner = document.getElementById('qtspinner');
+ var canvas = document.getElementById('qtcanvas');
+ var status = document.getElementById('qtstatus')
var qtLoader = QtLoader({
+ canvasElements : [canvas],
showLoader: function(loaderStatus) {
spinner.style.display = 'block';
canvas.style.display = 'none';
@@ -54,7 +55,6 @@
showCanvas: function() {
spinner.style.display = 'none';
canvas.style.display = 'block';
- return canvas;
},
});
qtLoader.loadEmscriptenModule("APPNAME");