Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwasmintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwasmintegration.h"
6#include "qwasmcompositor.h"
8#include "qwasmtheme.h"
9#include "qwasmclipboard.h"
10#include "qwasmaccessibility.h"
11#include "qwasmservices.h"
13#include "qwasmplatform.h"
14#include "qwasmwindow.h"
15#include "qwasmbackingstore.h"
16#include "qwasmfontdatabase.h"
17#include "qwasmdrag.h"
18
19#include <qpa/qplatformwindow.h>
20#include <QtGui/qscreen.h>
21#include <qpa/qwindowsysteminterface.h>
22#include <QtCore/qcoreapplication.h>
23#include <qpa/qplatforminputcontextfactory_p.h>
24#include <qpa/qwindowsysteminterface_p.h>
25
26#include <emscripten/bind.h>
27#include <emscripten/val.h>
28
29// this is where EGL headers are pulled in, make sure it is last
30#include "qwasmscreen.h"
31#include <private/qsimpledrag_p.h>
32
34
35extern void qt_set_sequence_auto_mnemonic(bool);
36
37using namespace emscripten;
38
39using namespace Qt::StringLiterals;
40
41static void setContainerElements(emscripten::val elementArray)
42{
43 QWasmIntegration::get()->setContainerElements(elementArray);
44}
45
46static void addContainerElement(emscripten::val element)
47{
48 QWasmIntegration::get()->addContainerElement(element);
49}
50
51static void removeContainerElement(emscripten::val element)
52{
53 QWasmIntegration::get()->removeContainerElement(element);
54}
55
56static void resizeContainerElement(emscripten::val element)
57{
58 QWasmIntegration::get()->resizeScreen(element);
59}
60
61static void qtUpdateDpi()
62{
63 QWasmIntegration::get()->updateDpi();
64}
65
66static void resizeAllScreens(emscripten::val event)
67{
69 QWasmIntegration::get()->resizeAllScreens();
70}
71
72static void loadLocalFontFamilies(emscripten::val event)
73{
74 QWasmIntegration::get()->loadLocalFontFamilies(event);
75}
76
77EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
78{
79 function("qtSetContainerElements", &setContainerElements);
80 function("qtAddContainerElement", &addContainerElement);
81 function("qtRemoveContainerElement", &removeContainerElement);
82 function("qtResizeContainerElement", &resizeContainerElement);
83 function("qtUpdateDpi", &qtUpdateDpi);
84 function("qtResizeAllScreens", &resizeAllScreens);
85 function("qtLoadLocalFontFamilies", &loadLocalFontFamilies);
86}
87
88QWasmIntegration *QWasmIntegration::s_instance;
89
91 : m_fontDb(nullptr)
92 , m_desktopServices(nullptr)
93 , m_clipboard(new QWasmClipboard)
94#if QT_CONFIG(accessibility)
95 , m_accessibility(new QWasmAccessibility)
96#endif
97{
98 s_instance = this;
99
100 if (platform() == Platform::MacOS)
102
103 touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>();
105
106 // Create screens for container elements. Each container element will ultimately become a
107 // div element. Qt historically supported supplying canvas for screen elements - these elements
108 // will be transformed into divs and warnings about deprecation will be printed. See
109 // QWasmScreen ctor.
110 emscripten::val filtered = emscripten::val::array();
111 emscripten::val qtContainerElements = val::module_property("qtContainerElements");
112 if (qtContainerElements.isArray()) {
113 for (int i = 0; i < qtContainerElements["length"].as<int>(); ++i) {
114 emscripten::val element = qtContainerElements[i].as<emscripten::val>();
115 if (element.isNull() || element.isUndefined())
116 qWarning() << "Skipping null or undefined element in qtContainerElements";
117 else
118 filtered.call<void>("push", element);
119 }
120 } else {
121 // No screens, which may or may not be intended
122 qWarning() << "The qtContainerElements module property was not set or is invalid. "
123 "Proceeding with no screens.";
124 }
125 setContainerElements(filtered);
126
127 // install browser window resize handler
128 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE,
129 [](int, const EmscriptenUiEvent *, void *) -> int {
130 // This resize event is called when the HTML window is
131 // resized. Depending on the page layout the elements might
132 // also have been resized, so we update the Qt screen sizes
133 // (and canvas render sizes).
134 if (QWasmIntegration *integration = QWasmIntegration::get())
135 integration->resizeAllScreens();
136 return 0;
137 });
138
139 // install visualViewport resize handler which picks up size and scale change on mobile.
140 emscripten::val visualViewport = emscripten::val::global("window")["visualViewport"];
141 if (!visualViewport.isUndefined()) {
142 visualViewport.call<void>("addEventListener", val("resize"),
143 val::module_property("qtResizeAllScreens"));
144 }
145 m_drag = std::make_unique<QWasmDrag>();
146}
147
149{
150 // Remove event listener
151 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, nullptr);
152 emscripten::val visualViewport = emscripten::val::global("window")["visualViewport"];
153 if (!visualViewport.isUndefined()) {
154 visualViewport.call<void>("removeEventListener", val("resize"),
155 val::module_property("qtResizeAllScreens"));
156 }
157
158 delete m_fontDb;
159 delete m_desktopServices;
160 if (m_platformInputContext)
161 delete m_platformInputContext;
162#if QT_CONFIG(accessibility)
163 delete m_accessibility;
164#endif
165
166 for (const auto &elementAndScreen : m_screens)
167 elementAndScreen.wasmScreen->deleteScreen();
168
169 m_screens.clear();
170
171 s_instance = nullptr;
172}
173
175{
176 switch (cap) {
177 case ThreadedPixmaps: return true;
178 case OpenGL: return true;
179 case ThreadedOpenGL: return false;
180 case RasterGLSurface: return false; // to enable this you need to fix qopenglwidget and quickwidget for wasm
181 case MultipleWindows: return true;
182 case WindowManagement: return true;
183 case OpenGLOnRasterSurface: return true;
185 }
186}
187
189{
190 auto *wasmScreen = QWasmScreen::get(window->screen());
191 QWasmCompositor *compositor = wasmScreen->compositor();
192 return new QWasmWindow(window, wasmScreen->deadKeySupport(), compositor,
193 m_backingStores.value(window));
194}
195
197{
198 QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
200 m_backingStores.insert(window, backingStore);
201 return backingStore;
202}
203
205{
206 m_backingStores.remove(window);
207}
208
210{
212 {
213 for (const auto &elementAndScreen : m_screens) {
214 elementAndScreen.wasmScreen->compositor()->requestUpdate();
215 }
216 }
217}
218
219#ifndef QT_NO_OPENGL
224#endif
225
227{
229 if (icStrs.isEmpty() && touchPoints < 1)
230 return;
231
232 if (!icStrs.isEmpty())
233 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
234 else
235 m_inputContext.reset(new QWasmInputContext());
236}
237
239{
240 return m_inputContext.data();
241}
242
247
249{
250 if (m_fontDb == nullptr)
251 m_fontDb = new QWasmFontDatabase;
252
253 return m_fontDb;
254}
255
260
262{
263 switch (hint) {
264 case ShowIsFullScreen:
265 return true;
267 return platform() != Platform::MacOS;
268 default:
270 }
271}
272
274{
275 // Don't maximize dialogs or popups
276 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Popup))
277 return Qt::WindowNoState;
278
280}
281
283{
284 return QStringList() << "webassembly"_L1;
285}
286
288{
289 if (name == "webassembly"_L1)
290 return new QWasmTheme;
292}
293
295{
296 if (m_desktopServices == nullptr)
297 m_desktopServices = new QWasmServices();
298 return m_desktopServices;
299}
300
302{
303 return m_clipboard;
304}
305
306#ifndef QT_NO_ACCESSIBILITY
307QPlatformAccessibility *QWasmIntegration::accessibility() const
308{
309 return m_accessibility;
310}
311#endif
312
313void QWasmIntegration::setContainerElements(emscripten::val elementArray)
314{
315 const auto *primaryScreenBefore = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
316 QList<ScreenMapping> newScreens;
317
318 QList<QWasmScreen *> screensToDelete;
319 std::transform(m_screens.begin(), m_screens.end(), std::back_inserter(screensToDelete),
320 [](const ScreenMapping &mapping) { return mapping.wasmScreen; });
321
322 for (int i = 0; i < elementArray["length"].as<int>(); ++i) {
323 const auto element = elementArray[i];
324 const auto it = std::find_if(
325 m_screens.begin(), m_screens.end(),
326 [&element](const ScreenMapping &screen) { return screen.emscriptenVal == element; });
328 if (it != m_screens.end()) {
329 screen = it->wasmScreen;
330 screensToDelete.erase(std::remove_if(screensToDelete.begin(), screensToDelete.end(),
331 [screen](const QWasmScreen *removedScreen) {
332 return removedScreen == screen;
333 }),
334 screensToDelete.end());
335 } else {
336 screen = new QWasmScreen(element);
338 }
339 newScreens.push_back({element, screen});
340 }
341
342 std::for_each(screensToDelete.begin(), screensToDelete.end(),
343 [](QWasmScreen *removed) { removed->deleteScreen(); });
344
345 m_screens = newScreens;
346 auto *primaryScreenAfter = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
347 if (primaryScreenAfter && primaryScreenAfter != primaryScreenBefore)
349}
350
351void QWasmIntegration::addContainerElement(emscripten::val element)
352{
353 Q_ASSERT_X(m_screens.end()
354 == std::find_if(m_screens.begin(), m_screens.end(),
355 [&element](const ScreenMapping &screen) {
356 return screen.emscriptenVal == element;
357 }),
358 Q_FUNC_INFO, "Double-add of an element");
359
360 QWasmScreen *screen = new QWasmScreen(element);
362 m_screens.push_back({element, screen});
363}
364
365void QWasmIntegration::removeContainerElement(emscripten::val element)
366{
367 const auto *primaryScreenBefore = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
368
369 const auto it =
370 std::find_if(m_screens.begin(), m_screens.end(),
371 [&element](const ScreenMapping &screen) { return screen.emscriptenVal == element; });
372 if (it == m_screens.end()) {
373 qWarning() << "Attempt to remove a nonexistent screen.";
374 return;
375 }
376
377 QWasmScreen *removedScreen = it->wasmScreen;
378 removedScreen->deleteScreen();
379
380 m_screens.erase(std::remove_if(m_screens.begin(), m_screens.end(),
381 [removedScreen](const ScreenMapping &mapping) {
382 return removedScreen == mapping.wasmScreen;
383 }),
384 m_screens.end());
385 auto *primaryScreenAfter = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
386 if (primaryScreenAfter && primaryScreenAfter != primaryScreenBefore)
388}
389
390void QWasmIntegration::resizeScreen(const emscripten::val &element)
391{
392 auto it = std::find_if(m_screens.begin(), m_screens.end(),
393 [&] (const ScreenMapping &candidate) { return candidate.emscriptenVal.equals(element); });
394 if (it == m_screens.end()) {
395 qWarning() << "Attempting to resize non-existing screen for element"
396 << QString::fromEcmaString(element["id"]);
397 return;
398 }
399 it->wasmScreen->updateQScreenAndCanvasRenderSize();
400}
401
403{
404 emscripten::val dpi = emscripten::val::module_property("qtFontDpi");
405 if (dpi.isUndefined())
406 return;
407 qreal dpiValue = dpi.as<qreal>();
408 for (const auto &elementAndScreen : m_screens)
409 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(elementAndScreen.wasmScreen->screen(), dpiValue, dpiValue);
410}
411
413{
414 for (const auto &elementAndScreen : m_screens)
415 elementAndScreen.wasmScreen->updateQScreenAndCanvasRenderSize();
416}
417
418void QWasmIntegration::loadLocalFontFamilies(emscripten::val families)
419{
420 m_fontDb->populateLocalFontFamilies(families);
421}
422
424{
425 return emscripten_performance_now();
426}
427
428#if QT_CONFIG(draganddrop)
429QPlatformDrag *QWasmIntegration::drag() const
430{
431 return m_drag.get();
432}
433#endif // QT_CONFIG(draganddrop)
434
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
T value(const Key &key) const noexcept
Definition qhash.h:1054
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
bool isEmpty() const noexcept
Definition qlist.h:401
iterator erase(const_iterator begin, const_iterator end)
Definition qlist.h:889
void push_back(parameter_type t)
Definition qlist.h:675
iterator end()
Definition qlist.h:626
iterator begin()
Definition qlist.h:625
void clear()
Definition qlist.h:434
\inmodule QtGui
\inmodule QtGui
The QPlatformBackingStore class provides the drawing area for top-level windows.
The QPlatformClipboard class provides an abstraction for the system clipboard.
The QPlatformDrag class provides an abstraction for drag.
The QPlatformFontDatabase class makes it possible to customize how fonts are discovered and how they ...
static QPlatformInputContext * create()
The QPlatformInputContext class abstracts the input method dependent data and composing state.
virtual QVariant styleHint(StyleHint hint) const
virtual Qt::WindowState defaultWindowState(Qt::WindowFlags) const
virtual bool hasCapability(Capability cap) const
virtual QPlatformTheme * createPlatformTheme(const QString &name) const
Capability
Capabilities are used to determine specific features of a platform integration.
The QPlatformOpenGLContext class provides an abstraction for native GL contexts.
The QPlatformServices provides the backend for desktop-related functionality.
The QPlatformTheme class allows customizing the UI based on themes.
The QPlatformWindow class provides an abstraction for top-level windows.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
iterator erase(const_iterator i)
Definition qset.h:145
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qvariant.h:65
static bool releaseRequestUpdateHold()
void populateLocalFontFamilies(emscripten::val families)
QPlatformInputContext * inputContext() const override
Returns the platforms input context.
void setContainerElements(emscripten::val elementArray)
static QWasmIntegration * get()
Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const override
QPlatformFontDatabase * fontDatabase() const override
Accessor for the platform integration's fontdatabase.
QPlatformOffscreenSurface * createPlatformOffscreenSurface(QOffscreenSurface *surface) const override
Factory function for QOffscreenSurface.
void addContainerElement(emscripten::val elementArray)
void initialize() override
Performs initialization steps that depend on having an event dispatcher available.
void removeContainerElement(emscripten::val elementArray)
QAbstractEventDispatcher * createEventDispatcher() const override
Factory function for the GUI event dispatcher.
QStringList themeNames() const override
void loadLocalFontFamilies(emscripten::val families)
QPlatformOpenGLContext * createPlatformOpenGLContext(QOpenGLContext *context) const override
Factory function for QPlatformOpenGLContext.
void removeBackingStore(QWindow *window)
QPlatformBackingStore * createPlatformBackingStore(QWindow *window) const override
Factory function for QPlatformBackingStore.
static quint64 getTimestamp()
QPlatformServices * services() const override
QPlatformClipboard * clipboard() const override
Accessor for the platform integration's clipboard.
QPlatformTheme * createPlatformTheme(const QString &name) const override
void resizeScreen(const emscripten::val &canvas)
QVariant styleHint(QPlatformIntegration::StyleHint hint) const override
bool hasCapability(QPlatformIntegration::Capability cap) const override
QPlatformWindow * createPlatformWindow(QWindow *window) const override
Factory function for QPlatformWindow.
QPlatformAccessibility * accessibility() const override
static QWasmScreen * get(QPlatformScreen *screen)
static void handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
Should be called whenever the primary screen changes.
static void handleScreenAdded(QPlatformScreen *screen, bool isPrimary=false)
Should be called by the implementation whenever a new screen is added.
static void handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal newDpiX, qreal newDpiY)
\inmodule QtGui
Definition qwindow.h:63
QSet< QString >::iterator it
Combined button and popup list for selecting options.
WindowState
Definition qnamespace.h:251
@ WindowNoState
Definition qnamespace.h:252
@ Popup
Definition qnamespace.h:211
@ Dialog
Definition qnamespace.h:208
static void * context
#define Q_FUNC_INFO
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b)
#define qWarning
Definition qlogging.h:166
static QOpenGLCompositor * compositor
GLbitfield flags
GLuint name
struct _cl_event * event
GLuint GLfloat * val
GLenum GLenum GLenum GLenum mapping
GLenum cap
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
QScreen * screen
[1]
Definition main.cpp:29
#define QT_CONFIG(feature)
#define Q_UNUSED(x)
unsigned long long quint64
Definition qtypes.h:61
double qreal
Definition qtypes.h:187
EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
static void addContainerElement(emscripten::val element)
static void removeContainerElement(emscripten::val element)
QT_BEGIN_NAMESPACE void qt_set_sequence_auto_mnemonic(bool)
static void loadLocalFontFamilies(emscripten::val event)
static void resizeAllScreens(emscripten::val event)
static void resizeContainerElement(emscripten::val element)
static void setContainerElements(emscripten::val elementArray)
static void qtUpdateDpi()
QT_BEGIN_NAMESPACE Platform platform()
if(qFloatDistance(a, b)<(1<< 7))
[0]
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]