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
4#include <qpa/qwindowsysteminterface.h>
5#include <private/qguiapplication_p.h>
6#include <QtCore/qfile.h>
7#include <QtGui/private/qwindow_p.h>
8#include <QtGui/private/qhighdpiscaling_p.h>
9#include <private/qpixmapcache_p.h>
10#include <QtGui/qopenglfunctions.h>
11#include <QBuffer>
12
14#include "qwasmdom.h"
15#if QT_CONFIG(clipboard)
16#include "qwasmclipboard.h"
17#endif
20#include "qwasmwindow.h"
21#include "qwasmscreen.h"
23#include "qwasmevent.h"
26#if QT_CONFIG(draganddrop)
27#include "qwasmdrag.h"
28#endif
30
31#include <iostream>
32#include <sstream>
33
34#include <emscripten/val.h>
35
36#include <QtCore/private/qstdweb_p.h>
37#include <QKeySequence>
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 flexbox to shrink correctly
459 m_window["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
460
461 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
462
463 m_canvas.set("width", canvasSize.width());
464 m_canvas.set("height", canvasSize.height());
465
466 bool shouldInvalidate = true;
467 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
468 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
469 m_normalGeometry = clientAreaRect;
470 }
471
472 QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
473 if (wasmInput && (QGuiApplication::focusWindow() == window()))
474 wasmInput->updateGeometry();
475
476 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
477 if (shouldInvalidate)
478 invalidate();
479 else
480 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()));
481}
482
483void QWasmWindow::setVisible(bool visible)
484{
485 // TODO(mikolajboc): isVisible()?
486 const bool nowVisible = m_decoratedWindow["style"]["display"].as<std::string>() == "block";
487 if (visible == nowVisible)
488 return;
489
490 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::ExposeEventDelivery);
491 m_decoratedWindow["style"].set("display", visible ? "block" : "none");
492 if (window() == QGuiApplication::focusWindow())
493 focus();
494
495 if (visible) {
496 applyWindowState();
497#if QT_CONFIG(accessibility)
498 QWasmAccessibility::onShowWindow(window());
499#endif
500 }
501}
502
504{
505 return window()->isVisible();
506}
507
509{
510 const auto frameRect =
511 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>("getBoundingClientRect"));
512 const auto canvasRect =
513 QRectF::fromDOMRect(m_window.call<emscripten::val>("getBoundingClientRect"));
514 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
515 frameRect.right() - canvasRect.right(),
516 frameRect.bottom() - canvasRect.bottom())
517 .toMargins();
518}
519
521{
522 bringToTop();
523 invalidate();
524}
525
527{
528 sendToBottom();
529 invalidate();
530}
531
533{
534 return m_winId;
535}
536
538{
539 // setGeometry() will take care of minimum and maximum size constraints
540 setGeometry(windowGeometry());
541 m_nonClientArea->propagateSizeHints();
542}
543
544void QWasmWindow::setOpacity(qreal level)
545{
546 m_decoratedWindow["style"].set("opacity", qBound(0.0, level, 1.0));
547}
548
549void QWasmWindow::invalidate()
550{
551 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()));
552}
553
555{
556 dom::syncCSSClassWith(m_decoratedWindow, "inactive", !active);
557}
558
559void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
560{
561 flags = fixTopLevelWindowFlags(flags);
562
563 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
564 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
565 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
566 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
567 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
568 }
569 m_flags = flags;
570 dom::syncCSSClassWith(m_decoratedWindow, "frameless", !hasFrame() || !window()->isTopLevel());
571 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
572 dom::syncCSSClassWith(m_decoratedWindow, "has-shadow", hasShadow());
573 dom::syncCSSClassWith(m_decoratedWindow, "has-title", hasTitleBar());
574 dom::syncCSSClassWith(m_decoratedWindow, "transparent-for-input",
575 flags.testFlag(Qt::WindowTransparentForInput));
576
577 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
578 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
579}
580
581void QWasmWindow::setWindowState(Qt::WindowStates newState)
582{
583 // Child windows can not have window states other than Qt::WindowActive
584 if (parent())
585 newState &= Qt::WindowActive;
586
587 const Qt::WindowStates oldState = m_state;
588
589 if (newState.testFlag(Qt::WindowMinimized)) {
590 newState.setFlag(Qt::WindowMinimized, false);
591 qWarning("Qt::WindowMinimized is not implemented in wasm");
592 window()->setWindowStates(newState);
593 return;
594 }
595
596 if (newState == oldState)
597 return;
598
599 m_state = newState;
600 m_previousWindowState = oldState;
601
602 applyWindowState();
603}
604
605void QWasmWindow::setWindowTitle(const QString &title)
606{
607 m_nonClientArea->titleBar()->setTitle(title);
608}
609
610void QWasmWindow::setWindowIcon(const QIcon &icon)
611{
612 const auto dpi = screen()->devicePixelRatio();
613 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
614 if (pixmap.isNull()) {
615 m_nonClientArea->titleBar()->setIcon(
616 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo), "svg+xml");
617 return;
618 }
619
620 QByteArray bytes;
621 QBuffer buffer(&bytes);
622 pixmap.save(&buffer, "png");
623 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(), "png");
624}
625
626void QWasmWindow::applyWindowState()
627{
628 QRect newGeom;
629
630 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
631 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
632 if (isFullscreen)
633 newGeom = platformScreen()->geometry();
634 else if (isMaximized)
635 newGeom = platformScreen()->availableGeometry().marginsRemoved(frameMargins());
636 else
637 newGeom = normalGeometry();
638
639 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
640 dom::syncCSSClassWith(m_decoratedWindow, "maximized", isMaximized);
641
642 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
643 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
644
645 if (isVisible())
646 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
647 setGeometry(newGeom);
648}
649
650void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
651{
652 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
653 m_commitedParent = parent;
654}
655
656void QWasmWindow::handleKeyEvent(const KeyEvent &event)
657{
658 qCDebug(qLcQpaWasmInputContext) << "handleKeyEvent";
659
660 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) {
661 handleKeyForInputContextEvent(event);
662 } else {
663 if (processKey(event)) {
664 event.webEvent.call<void>("preventDefault");
665 event.webEvent.call<void>("stopPropagation");
666 }
667 }
668}
669
670bool QWasmWindow::processKey(const KeyEvent &event)
671{
672 constexpr bool ProceedToNativeEvent = false;
673 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
674
675#if QT_CONFIG(clipboard)
676 const auto clipboardResult =
677 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
678
679 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
680 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
681 return ProceedToNativeEvent;
682#endif
683
684 const auto result = QWindowSystemInterface::handleKeyEvent(
685 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
686 event.modifiers, event.text, event.autoRepeat);
687
688#if QT_CONFIG(clipboard)
689 return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
690 ? ProceedToNativeEvent
691 : result;
692#else
693 return result;
694#endif
695}
696
697void QWasmWindow::handleKeyForInputContextEvent(const KeyEvent &keyEvent)
698{
699 // Don't send Qt key events if the key event is a part of input composition,
700 // let those be handled by by the input event key handler. Check for the
701 // keyCode 229 as well as isComposing in order catch all cases (see mdn
702 // docs for the keyDown event)
703 if (keyEvent.isComposing || keyEvent.keyCode == 229)
704 return;
705
706 qCDebug(qLcQpaWasmInputContext) << "processKey as KeyEvent";
707 emscripten::val event = keyEvent.webEvent;
708 if (processKeyForInputContext(keyEvent))
709 event.call<void>("preventDefault");
710 event.call<void>("stopImmediatePropagation");
711}
712
713bool QWasmWindow::processKeyForInputContext(const KeyEvent &event)
714{
715 qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
716 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
717
718 QKeySequence keySeq(event.modifiers | event.key);
719
720 if (keySeq == QKeySequence::Paste) {
721 // Process it in pasteCallback and inputCallback
722 return false;
723 }
724
725 const auto result = QWindowSystemInterface::handleKeyEvent(
726 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
727 event.modifiers, event.text);
728
729#if QT_CONFIG(clipboard)
730 // Copy/Cut callback required to copy qtClipboard to system clipboard
731 if (keySeq == QKeySequence::Copy || keySeq == QKeySequence::Cut)
732 return false;
733#endif
734
735 return result;
736}
737
738void QWasmWindow::handleInputEvent(emscripten::val event)
739{
740 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
741 inputContext->inputCallback(event);
742 else
743 m_focusHelper.set("innerHTML", std::string());
744}
745
746void QWasmWindow::handleCompositionStartEvent(emscripten::val event)
747{
748 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
749 inputContext->compositionStartCallback(event);
750 else
751 m_focusHelper.set("innerHTML", std::string());
752}
753
754void QWasmWindow::handleCompositionUpdateEvent(emscripten::val event)
755{
756 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
757 inputContext->compositionUpdateCallback(event);
758 else
759 m_focusHelper.set("innerHTML", std::string());
760}
761
762void QWasmWindow::handleCompositionEndEvent(emscripten::val event)
763{
764 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
765 inputContext->compositionEndCallback(event);
766 else
767 m_focusHelper.set("innerHTML", std::string());
768}
769
770void QWasmWindow::handleBeforeInputEvent(emscripten::val event)
771{
772 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
773 inputContext->beforeInputCallback(event);
774 else
775 m_focusHelper.set("innerHTML", std::string());
776}
777
778void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event)
779{
780 if (processPointerEnterLeave(event))
781 event.webEvent.call<void>("preventDefault");
782}
783
784bool QWasmWindow::processPointerEnterLeave(const PointerEvent &event)
785{
787 return false;
788
789 switch (event.type) {
791 const auto pointInScreen = platformScreen()->mapFromLocal(
792 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
793 QWindowSystemInterface::handleEnterEvent(
794 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
795 break;
796 }
799 break;
800 default:
801 break;
802 }
803
804 return false;
805}
806
807void QWasmWindow::releasePointerGrab(const MouseEvent &event)
808{
809 // We check hasPointerCapture due to the implicit release
810 // browsers do.
811 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
812 m_window.call<bool>("hasPointerCapture", *m_capturedPointerId)) {
813 m_window.call<void>("releasePointerCapture", *m_capturedPointerId);
814 m_capturedPointerId = std::nullopt;
815 }
816}
817
818void QWasmWindow::processPointer(const PointerEvent &event)
819{
820 // Process pointer events targeted at the window only, and not
821 // for instance events for the accessibility elements.
822 if (!event.isTargetedForElement(m_window))
823 return;
824
825 switch (event.type) {
826 case EventType::PointerDown:
827 m_capturedPointerId = event.pointerId;
828 m_window.call<void>("setPointerCapture", event.pointerId);
829
830 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
831 != Qt::WindowDoesNotAcceptFocus
832 && window()->isTopLevel())
833 window()->requestActivate();
834 break;
836 releasePointerGrab(event);
837 break;
838 default:
839 break;
840 };
841
842 const bool eventAccepted = deliverPointerEvent(event);
843 if (!eventAccepted && event.type == EventType::PointerDown)
844 QGuiApplicationPrivate::instance()->closeAllPopups();
845
846 if (eventAccepted) {
847 event.webEvent.call<void>("preventDefault");
848 event.webEvent.call<void>("stopPropagation");
849 }
850}
851
852bool QWasmWindow::deliverPointerEvent(const PointerEvent &event)
853{
854 const auto pointInScreen = platformScreen()->mapFromLocal(
855 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
856
857 const auto geometryF = platformScreen()->geometry().toRectF();
858 const QPointF targetPointClippedToScreen(
859 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
860 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
861
862 if (event.pointerType == PointerType::Mouse) {
863 const QEvent::Type eventType =
864 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client);
865
866 return eventType != QEvent::None
867 && QWindowSystemInterface::handleMouseEvent(
868 window(), QWasmIntegration::getTimestamp(),
869 window()->mapFromGlobal(targetPointClippedToScreen),
870 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
871 eventType, event.modifiers);
872 }
873
874 if (event.pointerType == PointerType::Pen) {
875 qreal pressure;
876 switch (event.type) {
879 pressure = event.pressure;
880 break;
882 pressure = 0.0;
883 break;
884 default:
885 return false;
886 }
887 // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
888 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
889 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
890 // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
891 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
892 return QWindowSystemInterface::handleTabletEvent(
893 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
894 window()->mapFromGlobal(targetPointClippedToScreen),
895 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
896 event.tangentialPressure, rotation, event.modifiers);
897 }
898
899 QWindowSystemInterface::TouchPoint *touchPoint;
900
901 QPointF pointInTargetWindowCoords =
902 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
903 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
904 pointInTargetWindowCoords.y() / window()->height());
905
906 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
907 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
908 touchPoint = &tp.value();
909 } else {
910 touchPoint = &m_pointerIdToTouchPoints
911 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
912 .value();
913
914 // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent()
915 // will not synthesize mouse events for touch points with negative id; use the absolute value for
916 // the touch point id.
917 touchPoint->id = qAbs(event.pointerId);
918
919 touchPoint->state = QEventPoint::State::Pressed;
920 }
921
922 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
923 touchPoint->normalPosition = normalPosition;
924 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
925 .translated(-event.width / 2, -event.height / 2);
926 touchPoint->pressure = event.pressure;
927
928 switch (event.type) {
929 case EventType::PointerUp:
930 touchPoint->state = QEventPoint::State::Released;
931 break;
932 case EventType::PointerMove:
933 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
934 : QEventPoint::State::Updated);
935 break;
936 default:
937 break;
938 }
939
940 QList<QWindowSystemInterface::TouchPoint> touchPointList;
941 touchPointList.reserve(m_pointerIdToTouchPoints.size());
942 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
943 std::back_inserter(touchPointList),
944 [](const QWindowSystemInterface::TouchPoint &val) { return val; });
945
946 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
947 m_pointerIdToTouchPoints.remove(event.pointerId);
948
949 return event.type == EventType::PointerCancel
950 ? QWindowSystemInterface::handleTouchCancelEvent(
951 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
952 event.modifiers)
953 : QWindowSystemInterface::handleTouchEvent(
954 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
955 touchPointList, event.modifiers);
956}
957
958void QWasmWindow::handleWheelEvent(const emscripten::val &event)
959{
960 if (processWheel(WheelEvent(EventType::Wheel, event)))
961 event.call<void>("preventDefault");
962}
963
964bool QWasmWindow::processWheel(const WheelEvent &event)
965{
966 // Web scroll deltas are inverted from Qt deltas - negate.
967 const int scrollFactor = -([&event]() {
968 switch (event.deltaMode) {
969 case DeltaMode::Pixel:
970 return 1;
971 case DeltaMode::Line:
972 return 12;
973 case DeltaMode::Page:
974 return 20;
975 };
976 })();
977
978 const auto pointInScreen = platformScreen()->mapFromLocal(
979 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
980
981 return QWindowSystemInterface::handleWheelEvent(
982 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
983 pointInScreen, (event.delta * scrollFactor).toPoint(),
984 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
985 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
986}
987
988// Fix top level window flags in case only the type flags are passed.
989Qt::WindowFlags QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags) const
990{
991 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
992 if (flags.testFlag(Qt::Window)) {
993 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
994 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
995 }
996 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
997 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
998
999 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1000 flags |= Qt::FramelessWindowHint;
1001 }
1002 return flags;
1003}
1004
1005bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
1006{
1007 if (!transientParent())
1008 return false;
1009
1010 if (isModal())
1011 return true;
1012
1013 if (flags.testFlag(Qt::Tool) ||
1014 flags.testFlag(Qt::SplashScreen) ||
1015 flags.testFlag(Qt::ToolTip) ||
1016 flags.testFlag(Qt::Popup))
1017 {
1018 return true;
1019 }
1020
1021 return false;
1022}
1023
1024QWasmWindowStack<>::PositionPreference QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags) const
1025{
1026 flags = fixTopLevelWindowFlags(flags);
1027
1028 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1029 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1030 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1031 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1032 if (shouldBeAboveTransientParentFlags(flags))
1033 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1034 return QWasmWindowStack<>::PositionPreference::Regular;
1035}
1036
1038{
1039 return m_normalGeometry;
1040}
1041
1043{
1044 return screen()->devicePixelRatio();
1045}
1046
1048{
1049 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::UpdateRequestDelivery);
1050}
1051
1052bool QWasmWindow::hasFrame() const
1053{
1054 return !m_flags.testFlag(Qt::FramelessWindowHint);
1055}
1056
1057bool QWasmWindow::hasBorder() const
1058{
1059 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1060 && !windowIsPopupType(m_flags) && !parent();
1061}
1062
1063bool QWasmWindow::hasTitleBar() const
1064{
1065 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1066}
1067
1068bool QWasmWindow::hasShadow() const
1069{
1070 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1071}
1072
1073bool QWasmWindow::hasMaximizeButton() const
1074{
1075 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1076}
1077
1078bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags) const
1079{
1080 if (flags.testFlag(Qt::Tool))
1081 return false; // Qt::Tool has the Popup bit set but isn't an actual Popup window
1082
1083 return (flags.testFlag(Qt::Popup));
1084}
1085
1087{
1088 QWindow *modalWindow;
1089 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1090 static_cast<QWasmWindow *>(modalWindow->handle())->requestActivateWindow();
1091 return;
1092 }
1093
1094 raise();
1095 setAsActiveNode();
1096
1097 if (!QWasmIntegration::get()->inputContext())
1098 focus();
1099 QPlatformWindow::requestActivateWindow();
1100}
1101
1103{
1104 if (QWasmAccessibility::isEnabled())
1105 return;
1106
1107 m_focusHelper.call<void>("focus");
1108}
1109
1111{
1112 m_focusHelper.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1113 m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1114}
1115
1117{
1118 Q_UNUSED(grab);
1119 return false;
1120}
1121
1122bool QWasmWindow::windowEvent(QEvent *event)
1123{
1124 switch (event->type()) {
1125 case QEvent::WindowBlocked:
1126 m_decoratedWindow["classList"].call<void>("add", emscripten::val("blocked"));
1127 return false; // Propagate further
1128 case QEvent::WindowUnblocked:;
1129 m_decoratedWindow["classList"].call<void>("remove", emscripten::val("blocked"));
1130 return false; // Propagate further
1131 default:
1132 return QPlatformWindow::windowEvent(event);
1133 }
1134}
1135
1136void QWasmWindow::setMask(const QRegion &region)
1137{
1138 if (region.isEmpty()) {
1139 m_decoratedWindow["style"].set("clipPath", emscripten::val(""));
1140 return;
1141 }
1142
1143 std::ostringstream cssClipPath;
1144 cssClipPath << "path('";
1145 for (const auto &rect : region) {
1146 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1147 cssClipPath << "M " << cssRect.left() << " " << cssRect.top() << " ";
1148 cssClipPath << "L " << cssRect.right() << " " << cssRect.top() << " ";
1149 cssClipPath << "L " << cssRect.right() << " " << cssRect.bottom() << " ";
1150 cssClipPath << "L " << cssRect.left() << " " << cssRect.bottom() << " z ";
1151 }
1152 cssClipPath << "')";
1153 m_decoratedWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
1154}
1155
1156void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1157{
1158 Q_UNUSED(newTransientParent);
1159
1160 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1161 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1162 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1163}
1164
1166{
1167 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1168 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1169 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1170}
1171
1172void QWasmWindow::setParent(const QPlatformWindow *)
1173{
1174 // The window flags depend on whether we are a
1175 // child window or not, so update them here.
1176 setWindowFlags(window()->flags());
1177
1178 commitParent(parentNode());
1179}
1180
1182{
1183 return "!qtwindow" + std::to_string(m_winId);
1184}
1185
1187{
1188 return m_window;
1189}
1190
1192{
1193 if (parent())
1194 return static_cast<QWasmWindow *>(parent());
1195 return platformScreen();
1196}
1197
1199{
1200 return this;
1201}
1202
1203void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
1204 QWasmWindowStack<>::PositionPreference positionPreference)
1205{
1206 if (previous)
1207 previous->containerElement().call<void>("removeChild", m_decoratedWindow);
1208 if (current)
1209 current->containerElement().call<void>("appendChild", m_decoratedWindow);
1210 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
1211}
1212
1213QT_END_NAMESPACE
QRect window() const
Returns the window rectangle.
QWasmCompositor(QWasmScreen *screen)
static QWasmIntegration * get()
static void destroyWebGLContext(QPlatformSurface *surface)
emscripten::val element() const
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:29
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:114
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)
DeltaMode
Definition qwasmevent.h:52
PointerType
Definition qwasmevent.h:40
EventType
Definition qwasmevent.h:22
WindowArea
Definition qwasmevent.h:47
int keyCode
Definition qwasmevent.h:75
bool isComposing
Definition qwasmevent.h:74
PointerType pointerType
Definition qwasmevent.h:129
DeltaMode deltaMode
Definition qwasmevent.h:158