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