Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwasmwindow.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// Qt-Security score:significant reason:default
4
5#include <qpa/qwindowsysteminterface.h>
6#include <private/qguiapplication_p.h>
7#include <QtCore/qfile.h>
8#include <QtGui/private/qwindow_p.h>
9#include <QtGui/private/qhighdpiscaling_p.h>
10#include <private/qpixmapcache_p.h>
11#include <QtGui/qopenglfunctions.h>
12#include <QBuffer>
13
15#include "qwasmdom.h"
16#if QT_CONFIG(clipboard)
17#include "qwasmclipboard.h"
18#endif
21#include "qwasmwindow.h"
22#include "qwasmscreen.h"
24#include "qwasmevent.h"
27#if QT_CONFIG(draganddrop)
28#include "qwasmdrag.h"
29#endif
31
32#include <iostream>
33#include <sstream>
34
35#include <emscripten/val.h>
36
37#include <QtCore/private/qstdweb_p.h>
38
40
42
44 QWasmCompositor *compositor, QWasmBackingStore *backingStore,
45 WId nativeHandle)
47 m_compositor(compositor),
48 m_backingStore(backingStore),
50 m_decoratedWindow(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
51 m_window(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
52 m_a11yContainer(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
53 m_canvas(m_document.call<emscripten::val>("createElement", emscripten::val("canvas"))),
54 m_focusHelper(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
55 m_inputElement(m_document.call<emscripten::val>("createElement", emscripten::val("input")))
56
57{
58 m_decoratedWindow.set("className", "qt-decorated-window");
59 m_decoratedWindow["style"].set("display", std::string("none"));
60
61 m_nonClientArea = std::make_unique<NonClientArea>(this, m_decoratedWindow);
62 m_nonClientArea->titleBar()->setTitle(window()->title());
63
64 // If we are wrapping a foregin window, a.k.a. a native html element then that element becomes
65 // the m_window element. In this case setting up event handlers and accessibility etc is not
66 // needed since that is (presumably) handled by the native html element.
67 //
68 // The WId is an emscripten::val *, owned by QWindow user code. We dereference and make
69 // a copy of the val here and don't strictly need it to be kept alive, but that's an
70 // implementation detail. The pointer will be dereferenced again if the window is destroyed
71 // and recreated.
72 if (nativeHandle) {
73 m_window = *(emscripten::val *)(nativeHandle);
74 m_winId = nativeHandle;
75 m_decoratedWindow.set("id", "qt-window-" + std::to_string(m_winId));
76 m_decoratedWindow.call<void>("appendChild", m_window);
77 return;
78 }
79
80 m_window.set("className", "qt-window");
81 m_decoratedWindow.call<void>("appendChild", m_window);
82
83 m_canvas["classList"].call<void>("add", emscripten::val("qt-window-canvas"));
84
85#if QT_CONFIG(clipboard)
86 if (QWasmClipboard::shouldInstallWindowEventHandlers()) {
87 m_cutCallback = QWasmEventHandler(m_canvas, "cut", QWasmClipboard::cut);
88 m_copyCallback = QWasmEventHandler(m_canvas, "copy", QWasmClipboard::copy);
89 m_pasteCallback = QWasmEventHandler(m_canvas, "paste", QWasmClipboard::paste);
90 }
91#endif
92
93 // Set up m_focusHelper, which is an invisible child element of the window which takes
94 // focus on behalf of the window any time the window has focus in general, but none
95 // of the special child elements such as the inputElment or a11y elements have focus.
96 // Set inputMode=none set to prevent the virtual keyboard from popping up.
97 m_focusHelper["classList"].call<void>("add", emscripten::val("qt-window-focus-helper"));
98 m_focusHelper.set("inputMode", std::string("none"));
99 m_focusHelper.call<void>("setAttribute", std::string("contenteditable"), std::string("true"));
100 m_focusHelper["style"].set("position", "absolute");
101 m_focusHelper["style"].set("left", 0);
102 m_focusHelper["style"].set("top", 0);
103 m_focusHelper["style"].set("width", "1px");
104 m_focusHelper["style"].set("height", "1px");
105 m_focusHelper["style"].set("z-index", -2);
106 m_focusHelper["style"].set("opacity", 0);
107 m_window.call<void>("appendChild", m_focusHelper);
108
109 // Set up m_inputElement, which takes focus whenever a Qt text input UI element has
110 // foucus.
111 m_inputElement["classList"].call<void>("add", emscripten::val("qt-window-input-element"));
112 m_inputElement.call<void>("setAttribute", std::string("contenteditable"), std::string("true"));
113 m_inputElement.set("type", "text");
114 m_inputElement["style"].set("position", "absolute");
115 m_inputElement["style"].set("left", 0);
116 m_inputElement["style"].set("top", 0);
117 m_inputElement["style"].set("width", "1px");
118 m_inputElement["style"].set("height", "1px");
119 m_inputElement["style"].set("z-index", -2);
120 m_inputElement["style"].set("opacity", 0);
121 m_inputElement["style"].set("display", "");
122 m_window.call<void>("appendChild", m_inputElement);
123
124 // The canvas displays graphics only, and is not accessible or an event target
125 m_canvas.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
126 m_canvas["style"].set("pointerEvents", "none");
127
128 m_window.call<void>("appendChild", m_canvas);
129
130 m_a11yContainer["classList"].call<void>("add", emscripten::val("qt-window-a11y-container"));
131 m_window.call<void>("appendChild", m_a11yContainer);
132
133 if (QWasmAccessibility::isEnabled())
135
136 const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
137 if (rendersTo2dContext)
138 m_context2d = m_canvas.call<emscripten::val>("getContext", emscripten::val("2d"));
139
140 m_winId = WId(&m_window);
141 m_decoratedWindow.set("id", "qt-window-" + std::to_string(m_winId));
142 emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas);
143
144 m_flags = window()->flags();
145
147
148 m_transientWindowChangedConnection =
149 QObject::connect(
150 window(), &QWindow::transientParentChanged,
151 window(), [this](QWindow *tp) { onTransientParentChanged(tp); });
152
153 m_modalityChangedConnection =
154 QObject::connect(
155 window(), &QWindow::modalityChanged,
156 window(), [this](Qt::WindowModality) { onModalityChanged(); });
157
158 setParent(parent());
159}
160
162{
163 m_pointerDownCallback = QWasmEventHandler(m_window, "pointerdown",
164 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); }
165 );
166 m_pointerMoveCallback = QWasmEventHandler(m_window, "pointermove",
167 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); }
168 );
169 m_pointerUpCallback = QWasmEventHandler(m_window, "pointerup",
170 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); }
171 );
172 m_pointerCancelCallback = QWasmEventHandler(m_window, "pointercancel",
173 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); }
174 );
175 m_pointerEnterCallback = QWasmEventHandler(m_window, "pointerenter",
176 [this](emscripten::val event) { this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); }
177 );
178 m_pointerLeaveCallback = QWasmEventHandler(m_window, "pointerleave",
179 [this](emscripten::val event) { this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); }
180 );
181
182#if QT_CONFIG(draganddrop)
183 m_window.call<void>("setAttribute", emscripten::val("draggable"), emscripten::val("true"));
184 m_dragStartCallback = QWasmEventHandler(m_window, "dragstart",
185 [this](emscripten::val event) {
186 DragEvent dragEvent(EventType::DragStart, event, window());
187 QWasmDrag::instance()->onNativeDragStarted(&dragEvent);
188 }
189 );
190 m_dragOverCallback = QWasmEventHandler(m_window, "dragover",
191 [this](emscripten::val event) {
192 DragEvent dragEvent(EventType::DragOver, event, window());
193 QWasmDrag::instance()->onNativeDragOver(&dragEvent);
194 }
195 );
196 m_dropCallback = QWasmEventHandler(m_window, "drop",
197 [this](emscripten::val event) {
198 DragEvent dragEvent(EventType::Drop, event, window());
199 QWasmDrag::instance()->onNativeDrop(&dragEvent);
200 }
201 );
202 m_dragEndCallback = QWasmEventHandler(m_window, "dragend",
203 [this](emscripten::val event) {
204 DragEvent dragEvent(EventType::DragEnd, event, window());
205 QWasmDrag::instance()->onNativeDragFinished(&dragEvent, platformScreen());
206 releasePointerGrab(dragEvent);
207 }
208 );
209 m_dragEnterCallback = QWasmEventHandler(m_window, "dragenter",
210 [this](emscripten::val event) {
211 DragEvent dragEvent(EventType::DragEnter, event, window());
212 QWasmDrag::instance()->onNativeDragEnter(&dragEvent);
213 }
214 );
215 m_dragLeaveCallback = QWasmEventHandler(m_window, "dragleave",
216 [this](emscripten::val event) {
217 DragEvent dragEvent(EventType::DragLeave, event, window());
218 QWasmDrag::instance()->onNativeDragLeave(&dragEvent);
219 }
220 );
221#endif // QT_CONFIG(draganddrop)
222
223 m_wheelEventCallback = QWasmEventHandler(m_window, "wheel",
224 [this](emscripten::val event) { this->handleWheelEvent(event); });
225
226 m_keyDownCallback = QWasmEventHandler(m_window, "keydown",
227 [this](emscripten::val event) { this->handleKeyEvent(KeyEvent(EventType::KeyDown, event)); });
228 m_keyUpCallback =QWasmEventHandler(m_window, "keyup",
229 [this](emscripten::val event) {this->handleKeyEvent(KeyEvent(EventType::KeyUp, event)); });
230
231 m_inputCallback = QWasmEventHandler(m_window, "input",
232 [this](emscripten::val event){ handleInputEvent(event); });
233 m_compositionUpdateCallback = QWasmEventHandler(m_window, "compositionupdate",
234 [this](emscripten::val event){ handleCompositionUpdateEvent(event); });
235 m_compositionStartCallback = QWasmEventHandler(m_window, "compositionstart",
236 [this](emscripten::val event){ handleCompositionStartEvent(event); });
237 m_compositionEndCallback = QWasmEventHandler(m_window, "compositionend",
238 [this](emscripten::val event){ handleCompositionEndEvent(event); });
239 m_beforeInputCallback = QWasmEventHandler(m_window, "beforeinput",
240 [this](emscripten::val event){ handleBeforeInputEvent(event); });
241 }
242
244{
246
247#if QT_CONFIG(accessibility)
248 QWasmAccessibility::onRemoveWindow(window());
249#endif
250 QObject::disconnect(m_transientWindowChangedConnection);
251 QObject::disconnect(m_modalityChangedConnection);
252
253 shutdown();
254
255 emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector());
256 m_window.call<void>("removeChild", m_canvas);
257 m_window.call<void>("removeChild", m_a11yContainer);
258 m_context2d = emscripten::val::undefined();
259 commitParent(nullptr);
260 if (m_requestAnimationFrameId > -1)
261 emscripten_cancel_animation_frame(m_requestAnimationFrameId);
262}
263
264void QWasmWindow::shutdown()
265{
266 if (!window() ||
267 (QGuiApplication::focusWindow() && // Don't act if we have a focus window different from this
268 QGuiApplication::focusWindow() != window()))
269 return;
270
271 // Make a list of all windows sorted on active index.
272 // Skip windows with active index 0 as they have
273 // never been active.
274 std::map<uint64_t, QWasmWindow *> allWindows;
275 for (const auto &w : platformScreen()->allWindows()) {
276 if (w->getActiveIndex() > 0)
277 allWindows.insert({w->getActiveIndex(), w});
278 }
279
280 // window is not in all windows
281 if (getActiveIndex() > 0)
282 allWindows.insert({getActiveIndex(), this});
283
284 if (allWindows.size() >= 2) {
285 const auto lastIt = std::prev(allWindows.end());
286 const auto prevIt = std::prev(lastIt);
287 const auto lastW = lastIt->second;
288 const auto prevW = prevIt->second;
289
290 if (lastW == this) // Only act if window is last to be active
291 prevW->requestActivateWindow();
292 }
293}
294
296{
297 return window()->requestedFormat();
298}
299
300QWasmWindow *QWasmWindow::fromWindow(const QWindow *window)
301{
302 if (!window ||!window->handle())
303 return nullptr;
304 return static_cast<QWasmWindow *>(window->handle());
305}
306
308{
309 if (!window())
310 return nullptr;
311
312 return fromWindow(window()->transientParent());
313}
314
316{
317 return window()->flags();
318}
319
320bool QWasmWindow::isModal() const
321{
322 return window()->isModal();
323}
324
326{
327 window()->setWindowState(Qt::WindowNoState);
328}
329
331{
332 window()->setWindowState(Qt::WindowMaximized);
333}
334
336{
337 window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
338 : Qt::WindowMaximized);
339}
340
342{
343 window()->close();
344}
345
347{
349 QGuiApplicationPrivate::instance()->closeAllPopups();
350}
351
353{
354 QPointF pointInScreen = platformScreen()->mapFromLocal(
355 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
356 return QWindowSystemInterface::handleMouseEvent(
357 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
358 pointInScreen, event.mouseButtons, event.mouseButton,
359 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
360 event.modifiers);
361}
362
364{
365 auto initialGeometry = QPlatformWindow::initialGeometry(window(),
366 windowGeometry(), defaultWindowSize, defaultWindowSize);
367 m_normalGeometry = initialGeometry;
368
369 setWindowState(window()->windowStates());
370 setWindowFlags(window()->flags());
371 setWindowTitle(window()->title());
372 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
373
374 if (window()->isTopLevel())
375 setWindowIcon(window()->icon());
376 QPlatformWindow::setGeometry(m_normalGeometry);
377
378#if QT_CONFIG(accessibility)
379 // Add accessibility-enable button. The user can activate this
380 // button to opt-in to accessibility.
381 if (window()->isTopLevel())
382 QWasmAccessibility::addAccessibilityEnableButton(window());
383#endif
384}
385
387{
388 return static_cast<QWasmScreen *>(window()->screen()->handle());
389}
390
392{
393 if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
394 return;
395
396 auto image = m_backingStore->getUpdatedWebImage(this);
397 if (image.isUndefined())
398 return;
399 m_context2d.call<void>("putImageData", image, emscripten::val(0), emscripten::val(0));
400}
401
403{
404 m_decoratedWindow["style"].set("zIndex", std::to_string(z));
405}
406
407void QWasmWindow::setWindowCursor(QByteArray cssCursorName)
408{
409 m_window["style"].set("cursor", emscripten::val(cssCursorName.constData()));
410}
411
412void QWasmWindow::setGeometry(const QRect &rect)
413{
414 const auto margins = frameMargins();
415
416 const QRect clientAreaRect = ([this, &rect, &margins]() {
417 if (m_state.testFlag(Qt::WindowFullScreen))
418 return platformScreen()->geometry();
419 if (m_state.testFlag(Qt::WindowMaximized))
420 return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
421
422 auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
423
424 // In viewport
425 auto containerGeometryInViewport =
426 QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
427 "getBoundingClientRect"))
428 .toRect();
429
430 auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
431
432 QRect cappedGeometry(rectInViewport);
433 if (!parent()) {
434 // Clamp top level windows top position to the screen bounds
435 cappedGeometry.moveTop(
436 std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
437 containerGeometryInViewport.y() + margins.top()));
438 }
439 cappedGeometry.setSize(
440 cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
441 return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
442 rect.size());
443 })();
444 m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
445
446 const auto frameRect =
447 clientAreaRect
448 .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
449 .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
450
451 m_decoratedWindow["style"].set("left", std::to_string(frameRect.left()) + "px");
452 m_decoratedWindow["style"].set("top", std::to_string(frameRect.top()) + "px");
453 m_canvas["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
454 m_canvas["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
455 m_a11yContainer["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
456 m_a11yContainer["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
457
458 // Important for the title bar and decorated window to size correctly
459 m_window["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
460 m_window["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
461
462 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
463
464 m_canvas.set("width", canvasSize.width());
465 m_canvas.set("height", canvasSize.height());
466
467 bool shouldInvalidate = true;
468 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
469 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
470 m_normalGeometry = clientAreaRect;
471 }
472
473 QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
474 if (wasmInput && (QGuiApplication::focusWindow() == window()))
475 wasmInput->updateGeometry();
476
477 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
478 if (shouldInvalidate)
479 invalidate();
480 else
481 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()));
482}
483
484void QWasmWindow::setVisible(bool visible)
485{
486 // TODO(mikolajboc): isVisible()?
487 const bool nowVisible = m_decoratedWindow["style"]["display"].as<std::string>() == "block";
488 if (visible == nowVisible)
489 return;
490
491 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::ExposeEventDelivery);
492 m_decoratedWindow["style"].set("display", visible ? "block" : "none");
493 if (window() == QGuiApplication::focusWindow())
494 focus();
495
496 if (visible) {
497 applyWindowState();
498#if QT_CONFIG(accessibility)
499 QWasmAccessibility::onShowWindow(window());
500#endif
501 }
502}
503
505{
506 return window()->isVisible();
507}
508
510{
511 const auto frameRect =
512 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>("getBoundingClientRect"));
513 const auto canvasRect =
514 QRectF::fromDOMRect(m_window.call<emscripten::val>("getBoundingClientRect"));
515 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
516 frameRect.right() - canvasRect.right(),
517 frameRect.bottom() - canvasRect.bottom())
518 .toMargins();
519}
520
522{
523 bringToTop();
524 invalidate();
525}
526
528{
529 sendToBottom();
530 invalidate();
531}
532
534{
535 return m_winId;
536}
537
539{
540 // setGeometry() will take care of minimum and maximum size constraints
541 setGeometry(windowGeometry());
542 m_nonClientArea->propagateSizeHints();
543}
544
545void QWasmWindow::setOpacity(qreal level)
546{
547 m_decoratedWindow["style"].set("opacity", qBound(0.0, level, 1.0));
548}
549
550void QWasmWindow::invalidate()
551{
552 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()));
553}
554
556{
557 dom::syncCSSClassWith(m_decoratedWindow, "inactive", !active);
558}
559
560void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
561{
562 flags = fixTopLevelWindowFlags(flags);
563
564 // Note: This function is also called from the constructor,
565 // and in this case we should not call onPositionPreferenceChanged
566 // since we haven't inserted the window yet.
567 if (std::find(childStack().begin(), childStack().end(), this) != childStack().end()) {
568 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
569 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
570 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
571 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
572 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
573 }
574 }
575 m_flags = flags;
576 dom::syncCSSClassWith(m_decoratedWindow, "frameless", !hasFrame() || !window()->isTopLevel());
577 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
578 dom::syncCSSClassWith(m_decoratedWindow, "has-shadow", hasShadow());
579 dom::syncCSSClassWith(m_decoratedWindow, "has-title", hasTitleBar());
580 dom::syncCSSClassWith(m_decoratedWindow, "transparent-for-input",
581 flags.testFlag(Qt::WindowTransparentForInput));
582
583 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
584 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
585}
586
587void QWasmWindow::setWindowState(Qt::WindowStates newState)
588{
589 // Child windows can not have window states other than Qt::WindowActive
590 if (parent())
591 newState &= Qt::WindowActive;
592
593 const Qt::WindowStates oldState = m_state;
594
595 if (newState.testFlag(Qt::WindowMinimized)) {
596 newState.setFlag(Qt::WindowMinimized, false);
597 qWarning("Qt::WindowMinimized is not implemented in wasm");
598 window()->setWindowStates(newState);
599 return;
600 }
601
602 if (newState == oldState)
603 return;
604
605 m_state = newState;
606 m_previousWindowState = oldState;
607
608 applyWindowState();
609}
610
611void QWasmWindow::setWindowTitle(const QString &title)
612{
613 m_nonClientArea->titleBar()->setTitle(title);
614}
615
616void QWasmWindow::setWindowIcon(const QIcon &icon)
617{
618 const auto dpi = screen()->devicePixelRatio();
619 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
620 if (pixmap.isNull()) {
621 m_nonClientArea->titleBar()->setIcon(
622 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo), "svg+xml");
623 return;
624 }
625
626 QByteArray bytes;
627 QBuffer buffer(&bytes);
628 pixmap.save(&buffer, "png");
629 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(), "png");
630}
631
632void QWasmWindow::applyWindowState()
633{
634 QRect newGeom;
635
636 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
637 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
638
639 // The screen geometry may be stale if the container element was hidden
640 // (display:none) when created — ResizeObserver doesn't fire for elements
641 // not in the layout. Re-read the geometry now so that fullscreen/maximized
642 // windows get the correct size.
643 if ((isFullscreen || isMaximized) && platformScreen()->geometry().size().isEmpty())
645
646 if (isFullscreen)
647 newGeom = platformScreen()->geometry();
648 else if (isMaximized)
649 newGeom = platformScreen()->availableGeometry().marginsRemoved(frameMargins());
650 else
651 newGeom = normalGeometry();
652
653 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
654 dom::syncCSSClassWith(m_decoratedWindow, "maximized", isMaximized);
655
656 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
657 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
658
659 if (isVisible())
660 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
661 setGeometry(newGeom);
662}
663
664void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
665{
666 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
667 m_commitedParent = parent;
668}
669
670void QWasmWindow::handleKeyEvent(const KeyEvent &event)
671{
672 qCDebug(qLcQpaWasmInputContext) << "handleKeyEvent";
673
674 if (QWasmInputContext *inputContext = activeWasmInputContext()) {
675 // Don't send Qt key events that are part of input composition; let the
676 // input event handler deal with those (keyCode 229 / isComposing).
677 if (event.isComposing || event.keyCode == 229)
678 return;
679 if (processKey(event)) {
680 // The key is already handled in Qt; flag the following input event
681 // so it is ignored by inputCallback (it still reaches it, to keep
682 // word suggestions working) instead of inserting the text twice.
683 inputContext->m_ignoreNextInput = true;
684 }
685 event.webEvent.call<void>("stopImmediatePropagation");
686 } else {
687 if (processKey(event)) {
688 event.webEvent.call<void>("preventDefault");
689 event.webEvent.call<void>("stopPropagation");
690 }
691 }
692}
693
694bool QWasmWindow::processKey(const KeyEvent &event)
695{
696 constexpr bool ProceedToNativeEvent = false;
697 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
698
699 // Copy/cut/paste shortcuts are partly serviced by the browser's native
700 // clipboard, which decides whether the event should be handed to the
701 // browser instead of (or in addition to) sending the Qt key event.
702#if QT_CONFIG(clipboard)
703 const auto clipboardResult =
704 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
705
706 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
707 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
708 return ProceedToNativeEvent;
709#endif
710
711 const auto result = QWindowSystemInterface::handleKeyEvent(
712 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
713 event.modifiers, event.text, event.autoRepeat);
714
715#if QT_CONFIG(clipboard)
716 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded)
717 return ProceedToNativeEvent;
718#endif
719
720 return result;
721}
722
723void QWasmWindow::handleInputEvent(emscripten::val event)
724{
725 if (QWasmInputContext *inputContext = activeWasmInputContext())
726 inputContext->inputCallback(event);
727 else
728 m_focusHelper.set("innerHTML", std::string());
729}
730
731void QWasmWindow::handleCompositionStartEvent(emscripten::val event)
732{
733 if (QWasmInputContext *inputContext = activeWasmInputContext())
734 inputContext->compositionStartCallback(event);
735 else
736 m_focusHelper.set("innerHTML", std::string());
737}
738
739void QWasmWindow::handleCompositionUpdateEvent(emscripten::val event)
740{
741 if (QWasmInputContext *inputContext = activeWasmInputContext())
742 inputContext->compositionUpdateCallback(event);
743 else
744 m_focusHelper.set("innerHTML", std::string());
745}
746
747void QWasmWindow::handleCompositionEndEvent(emscripten::val event)
748{
749 if (QWasmInputContext *inputContext = activeWasmInputContext())
750 inputContext->compositionEndCallback(event);
751 else
752 m_focusHelper.set("innerHTML", std::string());
753}
754
755void QWasmWindow::handleBeforeInputEvent(emscripten::val event)
756{
757 if (QWasmInputContext *inputContext = activeWasmInputContext())
758 inputContext->beforeInputCallback(event);
759 else
760 m_focusHelper.set("innerHTML", std::string());
761}
762
763void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event)
764{
765 if (processPointerEnterLeave(event))
766 event.webEvent.call<void>("preventDefault");
767}
768
769bool QWasmWindow::processPointerEnterLeave(const PointerEvent &event)
770{
772 return false;
773
774 switch (event.type) {
776 const auto pointInScreen = platformScreen()->mapFromLocal(
777 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
778 QWindowSystemInterface::handleEnterEvent(
779 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
780 break;
781 }
784 break;
785 default:
786 break;
787 }
788
789 return false;
790}
791
792void QWasmWindow::releasePointerGrab(const MouseEvent &event)
793{
794 // We check hasPointerCapture due to the implicit release
795 // browsers do.
796 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
797 m_window.call<bool>("hasPointerCapture", *m_capturedPointerId)) {
798 m_window.call<void>("releasePointerCapture", *m_capturedPointerId);
799 m_capturedPointerId = std::nullopt;
800 }
801}
802
803void QWasmWindow::processPointer(const PointerEvent &event)
804{
805 // Process pointer events targeted at the window only, and not
806 // for instance events for the accessibility elements.
807 if (!event.isTargetedForElement(m_window))
808 return;
809
810 switch (event.type) {
811 case EventType::PointerDown:
812 m_capturedPointerId = event.pointerId;
813 m_window.call<void>("setPointerCapture", event.pointerId);
814
815 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
816 != Qt::WindowDoesNotAcceptFocus
817 && window()->isTopLevel())
818 window()->requestActivate();
819 break;
821 releasePointerGrab(event);
822 break;
823 default:
824 break;
825 };
826
827 const bool eventAccepted = deliverPointerEvent(event);
828 if (!eventAccepted && event.type == EventType::PointerDown)
829 QGuiApplicationPrivate::instance()->closeAllPopups();
830
831 if (eventAccepted) {
832 event.webEvent.call<void>("preventDefault");
833 event.webEvent.call<void>("stopPropagation");
834 }
835}
836
837bool QWasmWindow::deliverPointerEvent(const PointerEvent &event)
838{
839 const auto pointInScreen = platformScreen()->mapFromLocal(
840 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
841
842 const auto geometryF = platformScreen()->geometry().toRectF();
843 const QPointF targetPointClippedToScreen(
844 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
845 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
846
847 if (event.pointerType == PointerType::Mouse) {
848 const QEvent::Type eventType =
849 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client);
850
851 return eventType != QEvent::None
852 && QWindowSystemInterface::handleMouseEvent(
853 window(), QWasmIntegration::getTimestamp(),
854 window()->mapFromGlobal(targetPointClippedToScreen),
855 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
856 eventType, event.modifiers);
857 }
858
859 if (event.pointerType == PointerType::Pen) {
860 qreal pressure;
861 switch (event.type) {
864 pressure = event.pressure;
865 break;
867 pressure = 0.0;
868 break;
869 default:
870 return false;
871 }
872 // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
873 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
874 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
875 // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
876 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
877 return QWindowSystemInterface::handleTabletEvent(
878 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
879 window()->mapFromGlobal(targetPointClippedToScreen),
880 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
881 event.tangentialPressure, rotation, event.modifiers);
882 }
883
884 QWindowSystemInterface::TouchPoint *touchPoint;
885
886 QPointF pointInTargetWindowCoords =
887 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
888 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
889 pointInTargetWindowCoords.y() / window()->height());
890
891 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
892 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
893 touchPoint = &tp.value();
894 } else {
895 touchPoint = &m_pointerIdToTouchPoints
896 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
897 .value();
898
899 // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent()
900 // will not synthesize mouse events for touch points with negative id; use the absolute value for
901 // the touch point id.
902 touchPoint->id = qAbs(event.pointerId);
903
904 touchPoint->state = QEventPoint::State::Pressed;
905 }
906
907 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
908 touchPoint->normalPosition = normalPosition;
909 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
910 .translated(-event.width / 2, -event.height / 2);
911 touchPoint->pressure = event.pressure;
912
913 switch (event.type) {
914 case EventType::PointerUp:
915 touchPoint->state = QEventPoint::State::Released;
916 break;
917 case EventType::PointerMove:
918 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
919 : QEventPoint::State::Updated);
920 break;
921 default:
922 break;
923 }
924
925 QList<QWindowSystemInterface::TouchPoint> touchPointList;
926 touchPointList.reserve(m_pointerIdToTouchPoints.size());
927 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
928 std::back_inserter(touchPointList),
929 [](const QWindowSystemInterface::TouchPoint &val) { return val; });
930
931 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
932 m_pointerIdToTouchPoints.remove(event.pointerId);
933
934 return event.type == EventType::PointerCancel
935 ? QWindowSystemInterface::handleTouchCancelEvent(
936 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
937 event.modifiers)
938 : QWindowSystemInterface::handleTouchEvent(
939 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
940 touchPointList, event.modifiers);
941}
942
943void QWasmWindow::handleWheelEvent(const emscripten::val &event)
944{
945 if (processWheel(WheelEvent(EventType::Wheel, event)))
946 event.call<void>("preventDefault");
947}
948
949bool QWasmWindow::processWheel(const WheelEvent &event)
950{
951 // Web scroll deltas are inverted from Qt deltas - negate.
952 const int scrollFactor = -([&event]() {
953 switch (event.deltaMode) {
954 case DeltaMode::Pixel:
955 return 1;
956 case DeltaMode::Line:
957 return 12;
958 case DeltaMode::Page:
959 return 20;
960 };
961 })();
962
963 const auto pointInScreen = platformScreen()->mapFromLocal(
964 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
965
966 return QWindowSystemInterface::handleWheelEvent(
967 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
968 pointInScreen, (event.delta * scrollFactor).toPoint(),
969 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
970 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
971}
972
973// Fix top level window flags in case only the type flags are passed.
974Qt::WindowFlags QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags) const
975{
976 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
977 if (flags.testFlag(Qt::Window)) {
978 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
979 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
980 }
981 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
982 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
983
984 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
985 flags |= Qt::FramelessWindowHint;
986 }
987 return flags;
988}
989
990bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
991{
993 return false;
994
995 if (isModal())
996 return true;
997
998 if (flags.testFlag(Qt::Tool) ||
999 flags.testFlag(Qt::SplashScreen) ||
1000 flags.testFlag(Qt::ToolTip) ||
1001 flags.testFlag(Qt::Popup))
1002 {
1003 return true;
1004 }
1005
1006 return false;
1007}
1008
1009QWasmWindowStack<>::PositionPreference QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags) const
1010{
1011 flags = fixTopLevelWindowFlags(flags);
1012
1013 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1014 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1015 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1016 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1017 if (shouldBeAboveTransientParentFlags(flags))
1018 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1019 return QWasmWindowStack<>::PositionPreference::Regular;
1020}
1021
1022// Returns the wasm input context if it exists and is active, otherwise nullptr.
1023QWasmInputContext *QWasmWindow::activeWasmInputContext() const
1024{
1025 QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext();
1026 return inputContext && inputContext->isActive() ? inputContext : nullptr;
1027}
1028
1030{
1031 return m_normalGeometry;
1032}
1033
1035{
1036 return screen()->devicePixelRatio();
1037}
1038
1040{
1041 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::UpdateRequestDelivery);
1042}
1043
1044bool QWasmWindow::hasFrame() const
1045{
1046 return !m_flags.testFlag(Qt::FramelessWindowHint);
1047}
1048
1049bool QWasmWindow::hasBorder() const
1050{
1051 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1052 && !windowIsPopupType(m_flags) && !parent();
1053}
1054
1055bool QWasmWindow::hasTitleBar() const
1056{
1057 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1058}
1059
1060bool QWasmWindow::hasShadow() const
1061{
1062 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1063}
1064
1065bool QWasmWindow::hasMaximizeButton() const
1066{
1067 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1068}
1069
1070bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags) const
1071{
1072 if (flags.testFlag(Qt::Tool))
1073 return false; // Qt::Tool has the Popup bit set but isn't an actual Popup window
1074
1075 return (flags.testFlag(Qt::Popup));
1076}
1077
1079{
1080 QWindow *modalWindow;
1081 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1082 static_cast<QWasmWindow *>(modalWindow->handle())->requestActivateWindow();
1083 return;
1084 }
1085
1086 raise();
1087 setAsActiveNode();
1088
1089 if (!QWasmIntegration::get()->inputContext())
1090 focus();
1091 QPlatformWindow::requestActivateWindow();
1092}
1093
1095{
1096 if (QWasmAccessibility::isEnabled())
1097 return;
1098
1099 m_focusHelper.call<void>("focus");
1100}
1101
1103{
1104 m_focusHelper.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1105 m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1106}
1107
1109{
1110 Q_UNUSED(grab);
1111 return false;
1112}
1113
1114bool QWasmWindow::windowEvent(QEvent *event)
1115{
1116 switch (event->type()) {
1117 case QEvent::WindowBlocked:
1118 m_decoratedWindow["classList"].call<void>("add", emscripten::val("blocked"));
1119 return false; // Propagate further
1120 case QEvent::WindowUnblocked:;
1121 m_decoratedWindow["classList"].call<void>("remove", emscripten::val("blocked"));
1122 return false; // Propagate further
1123 default:
1124 return QPlatformWindow::windowEvent(event);
1125 }
1126}
1127
1128void QWasmWindow::setMask(const QRegion &region)
1129{
1130 if (region.isEmpty()) {
1131 m_decoratedWindow["style"].set("clipPath", emscripten::val(""));
1132 return;
1133 }
1134
1135 std::ostringstream cssClipPath;
1136 cssClipPath << "path('";
1137 for (const auto &rect : region) {
1138 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1139 cssClipPath << "M " << cssRect.left() << " " << cssRect.top() << " ";
1140 cssClipPath << "L " << cssRect.right() << " " << cssRect.top() << " ";
1141 cssClipPath << "L " << cssRect.right() << " " << cssRect.bottom() << " ";
1142 cssClipPath << "L " << cssRect.left() << " " << cssRect.bottom() << " z ";
1143 }
1144 cssClipPath << "')";
1145 m_decoratedWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
1146}
1147
1148void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1149{
1150 Q_UNUSED(newTransientParent);
1151
1152 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1153 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1154 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1155}
1156
1158{
1159 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1160 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1161 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1162}
1163
1164void QWasmWindow::setParent(const QPlatformWindow *)
1165{
1166 // The window flags depend on whether we are a
1167 // child window or not, so update them here.
1168 setWindowFlags(window()->flags());
1169
1170 commitParent(parentNode());
1171}
1172
1174{
1175 return "!qtwindow" + std::to_string(m_winId);
1176}
1177
1179{
1180 return m_window;
1181}
1182
1184{
1185 if (parent())
1186 return static_cast<QWasmWindow *>(parent());
1187 return platformScreen();
1188}
1189
1191{
1192 return this;
1193}
1194
1195void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
1196 QWasmWindowStack<>::PositionPreference positionPreference)
1197{
1198 if (previous)
1199 previous->containerElement().call<void>("removeChild", m_decoratedWindow);
1200 if (current)
1201 current->containerElement().call<void>("appendChild", m_decoratedWindow);
1202 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
1203}
1204
1205QT_END_NAMESPACE
QRect window() const
Returns the window rectangle.
QWasmCompositor(QWasmScreen *screen)
static QWasmIntegration * get()
QWasmInputContext * wasmInputContext() const
static void destroyWebGLContext(QPlatformSurface *surface)
emscripten::val element() const
void updateQScreenSize()
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
void setVisible(bool visible) override
Reimplemented in subclasses to show the surface if visible is true, and hide it if visible is false.
qreal devicePixelRatio() const override
Reimplement this function in subclass to return the device pixel ratio for the window.
QRect normalGeometry() const override
Returns the geometry of a window in 'normal' state (neither maximized, fullscreen nor minimized) for ...
QSurfaceFormat format() const override
Returns the actual surface format of the window.
void setParent(const QPlatformWindow *window) final
This function is called to enable native child window in QPA.
static QWasmWindow * fromWindow(const QWindow *window)
void raise() override
Reimplement to be able to let Qt raise windows to the top of the desktop.
void setWindowTitle(const QString &title) override
Reimplement to set the window title to title.
void requestActivateWindow() override
Reimplement to let Qt be able to request activation/focus for a window.
WId winId() const override
Reimplement in subclasses to return a handle to the native window.
void onToggleMaximized()
std::string canvasSelector() const
QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore, WId nativeHandle)
friend class QWasmCompositor
void onNonClientAreaInteraction()
void setGeometry(const QRect &) override
This function is called by Qt whenever a window is moved or resized using the QWindow API.
bool setMouseGrabEnabled(bool grab) final
bool onNonClientEvent(const PointerEvent &event)
void setWindowCursor(QByteArray cssCursorName)
void setZOrder(int order)
void setMask(const QRegion &region) final
Reimplement to be able to let Qt set the mask of a window.
QWasmWindow * transientParent() const
QWasmWindowTreeNode * parentNode() final
void onModalityChanged()
void initialize() override
Called as part of QWindow::create(), after constructing the window.
bool isModal() const
Qt::WindowFlags windowFlags() const
bool isVisible() const
void registerEventHandlers()
~QWasmWindow() final
void onMaximizeClicked()
void requestUpdate() override
Requests an QEvent::UpdateRequest event.
void lower() override
Reimplement to be able to let Qt lower windows to the bottom of the desktop.
void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current, QWasmWindowStack<>::PositionPreference positionPreference) final
void onRestoreClicked()
void setOpacity(qreal level) override
Reimplement to be able to let Qt set the opacity level of a window.
void onActivationChanged(bool active)
void onAccessibilityEnable()
void setWindowState(Qt::WindowStates state) override
Requests setting the window state of this surface to type.
void setWindowIcon(const QIcon &icon) override
Reimplement to set the window icon to icon.
void propagateSizeHints() override
Reimplement to propagate the size hints of the QWindow.
QMargins frameMargins() const override
void onCloseClicked()
QWasmWindow * asWasmWindow() final
bool windowEvent(QEvent *event) final
Reimplement this method to be able to do any platform specific event handling.
QWasmScreen * platformScreen() const
emscripten::val containerElement() final
void setWindowFlags(Qt::WindowFlags flags) override
Requests setting the window flags of this surface to flags.
Definition qwasmdom.h:30
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:134
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)
DeltaMode
Definition qwasmevent.h:53
PointerType
Definition qwasmevent.h:41
EventType
Definition qwasmevent.h:23
WindowArea
Definition qwasmevent.h:48
int keyCode
Definition qwasmevent.h:76
bool isComposing
Definition qwasmevent.h:75
PointerType pointerType
Definition qwasmevent.h:130
DeltaMode deltaMode
Definition qwasmevent.h:159