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 // Note: This function is also called from the constructor,
566 // and in this case we should not call onPositionPreferenceChanged
567 // since we haven't inserted the window yet.
568 if (std::find(childStack().begin(), childStack().end(), this) != childStack().end()) {
569 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
570 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
571 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
572 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
573 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
574 }
575 }
576 m_flags = flags;
577 dom::syncCSSClassWith(m_decoratedWindow, "frameless", !hasFrame() || !window()->isTopLevel());
578 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
579 dom::syncCSSClassWith(m_decoratedWindow, "has-shadow", hasShadow());
580 dom::syncCSSClassWith(m_decoratedWindow, "has-title", hasTitleBar());
581 dom::syncCSSClassWith(m_decoratedWindow, "transparent-for-input",
582 flags.testFlag(Qt::WindowTransparentForInput));
583
584 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
585 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
586}
587
588void QWasmWindow::setWindowState(Qt::WindowStates newState)
589{
590 // Child windows can not have window states other than Qt::WindowActive
591 if (parent())
592 newState &= Qt::WindowActive;
593
594 const Qt::WindowStates oldState = m_state;
595
596 if (newState.testFlag(Qt::WindowMinimized)) {
597 newState.setFlag(Qt::WindowMinimized, false);
598 qWarning("Qt::WindowMinimized is not implemented in wasm");
599 window()->setWindowStates(newState);
600 return;
601 }
602
603 if (newState == oldState)
604 return;
605
606 m_state = newState;
607 m_previousWindowState = oldState;
608
609 applyWindowState();
610}
611
612void QWasmWindow::setWindowTitle(const QString &title)
613{
614 m_nonClientArea->titleBar()->setTitle(title);
615}
616
617void QWasmWindow::setWindowIcon(const QIcon &icon)
618{
619 const auto dpi = screen()->devicePixelRatio();
620 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
621 if (pixmap.isNull()) {
622 m_nonClientArea->titleBar()->setIcon(
623 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo), "svg+xml");
624 return;
625 }
626
627 QByteArray bytes;
628 QBuffer buffer(&bytes);
629 pixmap.save(&buffer, "png");
630 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(), "png");
631}
632
633void QWasmWindow::applyWindowState()
634{
635 QRect newGeom;
636
637 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
638 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
639
640 // The screen geometry may be stale if the container element was hidden
641 // (display:none) when created — ResizeObserver doesn't fire for elements
642 // not in the layout. Re-read the geometry now so that fullscreen/maximized
643 // windows get the correct size.
644 if ((isFullscreen || isMaximized) && platformScreen()->geometry().size().isEmpty())
646
647 if (isFullscreen)
648 newGeom = platformScreen()->geometry();
649 else if (isMaximized)
650 newGeom = platformScreen()->availableGeometry().marginsRemoved(frameMargins());
651 else
652 newGeom = normalGeometry();
653
654 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
655 dom::syncCSSClassWith(m_decoratedWindow, "maximized", isMaximized);
656
657 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
658 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
659
660 if (isVisible())
661 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
662 setGeometry(newGeom);
663}
664
665void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
666{
667 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
668 m_commitedParent = parent;
669}
670
671void QWasmWindow::handleKeyEvent(const KeyEvent &event)
672{
673 qCDebug(qLcQpaWasmInputContext) << "handleKeyEvent";
674
675 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) {
676 handleKeyForInputContextEvent(event);
677 } else {
678 if (processKey(event)) {
679 event.webEvent.call<void>("preventDefault");
680 event.webEvent.call<void>("stopPropagation");
681 }
682 }
683}
684
685bool QWasmWindow::processKey(const KeyEvent &event)
686{
687 constexpr bool ProceedToNativeEvent = false;
688 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
689
690#if QT_CONFIG(clipboard)
691 const auto clipboardResult =
692 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
693
694 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
695 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
696 return ProceedToNativeEvent;
697#endif
698
699 const auto result = QWindowSystemInterface::handleKeyEvent(
700 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
701 event.modifiers, event.text, event.autoRepeat);
702
703#if QT_CONFIG(clipboard)
704 return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
705 ? ProceedToNativeEvent
706 : result;
707#else
708 return result;
709#endif
710}
711
712void QWasmWindow::handleKeyForInputContextEvent(const KeyEvent &keyEvent)
713{
714 // Don't send Qt key events if the key event is a part of input composition,
715 // let those be handled by by the input event key handler. Check for the
716 // keyCode 229 as well as isComposing in order catch all cases (see mdn
717 // docs for the keyDown event)
718
719 if (keyEvent.isComposing || keyEvent.keyCode == 229)
720 return;
721
722 qCDebug(qLcQpaWasmInputContext) << "processKey as KeyEvent";
723 emscripten::val event = keyEvent.webEvent;
724 if (processKeyForInputContext(keyEvent)) {
725 // this event is already handled in Qt, but let it
726 // go to inputCallback to facilitate word suggestions
727 QWasmIntegration::get()->wasmInputContext()->m_ignoreNextInput = true;
728 }
729 event.call<void>("stopImmediatePropagation");
730}
731
732bool QWasmWindow::processKeyForInputContext(const KeyEvent &event)
733{
734 qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
735 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
736
737 QKeySequence keySeq(event.modifiers | event.key);
738
739 if (keySeq == QKeySequence::Paste) {
740 // Process it in pasteCallback and inputCallback
741 return false;
742 }
743
744 const auto result = QWindowSystemInterface::handleKeyEvent(
745 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
746 event.modifiers, event.text);
747
748#if QT_CONFIG(clipboard)
749 // Copy/Cut callback required to copy qtClipboard to system clipboard
750 if (keySeq == QKeySequence::Copy || keySeq == QKeySequence::Cut)
751 return false;
752#endif
753
754 return result;
755}
756
757void QWasmWindow::handleInputEvent(emscripten::val event)
758{
759 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
760 inputContext->inputCallback(event);
761 else
762 m_focusHelper.set("innerHTML", std::string());
763}
764
765void QWasmWindow::handleCompositionStartEvent(emscripten::val event)
766{
767 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
768 inputContext->compositionStartCallback(event);
769 else
770 m_focusHelper.set("innerHTML", std::string());
771}
772
773void QWasmWindow::handleCompositionUpdateEvent(emscripten::val event)
774{
775 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
776 inputContext->compositionUpdateCallback(event);
777 else
778 m_focusHelper.set("innerHTML", std::string());
779}
780
781void QWasmWindow::handleCompositionEndEvent(emscripten::val event)
782{
783 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
784 inputContext->compositionEndCallback(event);
785 else
786 m_focusHelper.set("innerHTML", std::string());
787}
788
789void QWasmWindow::handleBeforeInputEvent(emscripten::val event)
790{
791 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
792 inputContext->beforeInputCallback(event);
793 else
794 m_focusHelper.set("innerHTML", std::string());
795}
796
797void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event)
798{
799 if (processPointerEnterLeave(event))
800 event.webEvent.call<void>("preventDefault");
801}
802
803bool QWasmWindow::processPointerEnterLeave(const PointerEvent &event)
804{
806 return false;
807
808 switch (event.type) {
810 const auto pointInScreen = platformScreen()->mapFromLocal(
811 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
812 QWindowSystemInterface::handleEnterEvent(
813 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
814 break;
815 }
818 break;
819 default:
820 break;
821 }
822
823 return false;
824}
825
826void QWasmWindow::releasePointerGrab(const MouseEvent &event)
827{
828 // We check hasPointerCapture due to the implicit release
829 // browsers do.
830 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
831 m_window.call<bool>("hasPointerCapture", *m_capturedPointerId)) {
832 m_window.call<void>("releasePointerCapture", *m_capturedPointerId);
833 m_capturedPointerId = std::nullopt;
834 }
835}
836
837void QWasmWindow::processPointer(const PointerEvent &event)
838{
839 // Process pointer events targeted at the window only, and not
840 // for instance events for the accessibility elements.
841 if (!event.isTargetedForElement(m_window))
842 return;
843
844 switch (event.type) {
845 case EventType::PointerDown:
846 m_capturedPointerId = event.pointerId;
847 m_window.call<void>("setPointerCapture", event.pointerId);
848
849 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
850 != Qt::WindowDoesNotAcceptFocus
851 && window()->isTopLevel())
852 window()->requestActivate();
853 break;
855 releasePointerGrab(event);
856 break;
857 default:
858 break;
859 };
860
861 const bool eventAccepted = deliverPointerEvent(event);
862 if (!eventAccepted && event.type == EventType::PointerDown)
863 QGuiApplicationPrivate::instance()->closeAllPopups();
864
865 if (eventAccepted) {
866 event.webEvent.call<void>("preventDefault");
867 event.webEvent.call<void>("stopPropagation");
868 }
869}
870
871bool QWasmWindow::deliverPointerEvent(const PointerEvent &event)
872{
873 const auto pointInScreen = platformScreen()->mapFromLocal(
874 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
875
876 const auto geometryF = platformScreen()->geometry().toRectF();
877 const QPointF targetPointClippedToScreen(
878 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
879 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
880
881 if (event.pointerType == PointerType::Mouse) {
882 const QEvent::Type eventType =
883 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client);
884
885 return eventType != QEvent::None
886 && QWindowSystemInterface::handleMouseEvent(
887 window(), QWasmIntegration::getTimestamp(),
888 window()->mapFromGlobal(targetPointClippedToScreen),
889 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
890 eventType, event.modifiers);
891 }
892
893 if (event.pointerType == PointerType::Pen) {
894 qreal pressure;
895 switch (event.type) {
898 pressure = event.pressure;
899 break;
901 pressure = 0.0;
902 break;
903 default:
904 return false;
905 }
906 // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
907 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
908 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
909 // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
910 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
911 return QWindowSystemInterface::handleTabletEvent(
912 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
913 window()->mapFromGlobal(targetPointClippedToScreen),
914 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
915 event.tangentialPressure, rotation, event.modifiers);
916 }
917
918 QWindowSystemInterface::TouchPoint *touchPoint;
919
920 QPointF pointInTargetWindowCoords =
921 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
922 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
923 pointInTargetWindowCoords.y() / window()->height());
924
925 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
926 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
927 touchPoint = &tp.value();
928 } else {
929 touchPoint = &m_pointerIdToTouchPoints
930 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
931 .value();
932
933 // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent()
934 // will not synthesize mouse events for touch points with negative id; use the absolute value for
935 // the touch point id.
936 touchPoint->id = qAbs(event.pointerId);
937
938 touchPoint->state = QEventPoint::State::Pressed;
939 }
940
941 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
942 touchPoint->normalPosition = normalPosition;
943 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
944 .translated(-event.width / 2, -event.height / 2);
945 touchPoint->pressure = event.pressure;
946
947 switch (event.type) {
948 case EventType::PointerUp:
949 touchPoint->state = QEventPoint::State::Released;
950 break;
951 case EventType::PointerMove:
952 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
953 : QEventPoint::State::Updated);
954 break;
955 default:
956 break;
957 }
958
959 QList<QWindowSystemInterface::TouchPoint> touchPointList;
960 touchPointList.reserve(m_pointerIdToTouchPoints.size());
961 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
962 std::back_inserter(touchPointList),
963 [](const QWindowSystemInterface::TouchPoint &val) { return val; });
964
965 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
966 m_pointerIdToTouchPoints.remove(event.pointerId);
967
968 return event.type == EventType::PointerCancel
969 ? QWindowSystemInterface::handleTouchCancelEvent(
970 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
971 event.modifiers)
972 : QWindowSystemInterface::handleTouchEvent(
973 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
974 touchPointList, event.modifiers);
975}
976
977void QWasmWindow::handleWheelEvent(const emscripten::val &event)
978{
979 if (processWheel(WheelEvent(EventType::Wheel, event)))
980 event.call<void>("preventDefault");
981}
982
983bool QWasmWindow::processWheel(const WheelEvent &event)
984{
985 // Web scroll deltas are inverted from Qt deltas - negate.
986 const int scrollFactor = -([&event]() {
987 switch (event.deltaMode) {
988 case DeltaMode::Pixel:
989 return 1;
990 case DeltaMode::Line:
991 return 12;
992 case DeltaMode::Page:
993 return 20;
994 };
995 })();
996
997 const auto pointInScreen = platformScreen()->mapFromLocal(
998 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
999
1000 return QWindowSystemInterface::handleWheelEvent(
1001 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
1002 pointInScreen, (event.delta * scrollFactor).toPoint(),
1003 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
1004 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
1005}
1006
1007// Fix top level window flags in case only the type flags are passed.
1008Qt::WindowFlags QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags) const
1009{
1010 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
1011 if (flags.testFlag(Qt::Window)) {
1012 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1013 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
1014 }
1015 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
1016 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1017
1018 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1019 flags |= Qt::FramelessWindowHint;
1020 }
1021 return flags;
1022}
1023
1024bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
1025{
1026 if (!transientParent())
1027 return false;
1028
1029 if (isModal())
1030 return true;
1031
1032 if (flags.testFlag(Qt::Tool) ||
1033 flags.testFlag(Qt::SplashScreen) ||
1034 flags.testFlag(Qt::ToolTip) ||
1035 flags.testFlag(Qt::Popup))
1036 {
1037 return true;
1038 }
1039
1040 return false;
1041}
1042
1043QWasmWindowStack<>::PositionPreference QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags) const
1044{
1045 flags = fixTopLevelWindowFlags(flags);
1046
1047 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1048 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1049 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1050 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1051 if (shouldBeAboveTransientParentFlags(flags))
1052 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1053 return QWasmWindowStack<>::PositionPreference::Regular;
1054}
1055
1057{
1058 return m_normalGeometry;
1059}
1060
1062{
1063 return screen()->devicePixelRatio();
1064}
1065
1067{
1068 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::UpdateRequestDelivery);
1069}
1070
1071bool QWasmWindow::hasFrame() const
1072{
1073 return !m_flags.testFlag(Qt::FramelessWindowHint);
1074}
1075
1076bool QWasmWindow::hasBorder() const
1077{
1078 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1079 && !windowIsPopupType(m_flags) && !parent();
1080}
1081
1082bool QWasmWindow::hasTitleBar() const
1083{
1084 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1085}
1086
1087bool QWasmWindow::hasShadow() const
1088{
1089 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1090}
1091
1092bool QWasmWindow::hasMaximizeButton() const
1093{
1094 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1095}
1096
1097bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags) const
1098{
1099 if (flags.testFlag(Qt::Tool))
1100 return false; // Qt::Tool has the Popup bit set but isn't an actual Popup window
1101
1102 return (flags.testFlag(Qt::Popup));
1103}
1104
1106{
1107 QWindow *modalWindow;
1108 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1109 static_cast<QWasmWindow *>(modalWindow->handle())->requestActivateWindow();
1110 return;
1111 }
1112
1113 raise();
1114 setAsActiveNode();
1115
1116 if (!QWasmIntegration::get()->inputContext())
1117 focus();
1118 QPlatformWindow::requestActivateWindow();
1119}
1120
1122{
1123 if (QWasmAccessibility::isEnabled())
1124 return;
1125
1126 m_focusHelper.call<void>("focus");
1127}
1128
1130{
1131 m_focusHelper.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1132 m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1133}
1134
1136{
1137 Q_UNUSED(grab);
1138 return false;
1139}
1140
1141bool QWasmWindow::windowEvent(QEvent *event)
1142{
1143 switch (event->type()) {
1144 case QEvent::WindowBlocked:
1145 m_decoratedWindow["classList"].call<void>("add", emscripten::val("blocked"));
1146 return false; // Propagate further
1147 case QEvent::WindowUnblocked:;
1148 m_decoratedWindow["classList"].call<void>("remove", emscripten::val("blocked"));
1149 return false; // Propagate further
1150 default:
1151 return QPlatformWindow::windowEvent(event);
1152 }
1153}
1154
1155void QWasmWindow::setMask(const QRegion &region)
1156{
1157 if (region.isEmpty()) {
1158 m_decoratedWindow["style"].set("clipPath", emscripten::val(""));
1159 return;
1160 }
1161
1162 std::ostringstream cssClipPath;
1163 cssClipPath << "path('";
1164 for (const auto &rect : region) {
1165 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1166 cssClipPath << "M " << cssRect.left() << " " << cssRect.top() << " ";
1167 cssClipPath << "L " << cssRect.right() << " " << cssRect.top() << " ";
1168 cssClipPath << "L " << cssRect.right() << " " << cssRect.bottom() << " ";
1169 cssClipPath << "L " << cssRect.left() << " " << cssRect.bottom() << " z ";
1170 }
1171 cssClipPath << "')";
1172 m_decoratedWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
1173}
1174
1175void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1176{
1177 Q_UNUSED(newTransientParent);
1178
1179 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1180 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1181 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1182}
1183
1185{
1186 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1187 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1188 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1189}
1190
1191void QWasmWindow::setParent(const QPlatformWindow *)
1192{
1193 // The window flags depend on whether we are a
1194 // child window or not, so update them here.
1195 setWindowFlags(window()->flags());
1196
1197 commitParent(parentNode());
1198}
1199
1201{
1202 return "!qtwindow" + std::to_string(m_winId);
1203}
1204
1206{
1207 return m_window;
1208}
1209
1211{
1212 if (parent())
1213 return static_cast<QWasmWindow *>(parent());
1214 return platformScreen();
1215}
1216
1218{
1219 return this;
1220}
1221
1222void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
1223 QWasmWindowStack<>::PositionPreference positionPreference)
1224{
1225 if (previous)
1226 previous->containerElement().call<void>("removeChild", m_decoratedWindow);
1227 if (current)
1228 current->containerElement().call<void>("appendChild", m_decoratedWindow);
1229 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
1230}
1231
1232QT_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)
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