Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwasmwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <qpa/qwindowsysteminterface.h>
5#include <private/qguiapplication_p.h>
6#include <QtCore/qfile.h>
7#include <QtGui/private/qwindow_p.h>
8#include <QtGui/private/qhighdpiscaling_p.h>
9#include <private/qpixmapcache_p.h>
10#include <QtGui/qopenglfunctions.h>
11#include <QBuffer>
12
14#include "qwasmdom.h"
15#if QT_CONFIG(clipboard)
16#include "qwasmclipboard.h"
17#endif
20#include "qwasmwindow.h"
21#include "qwasmscreen.h"
23#include "qwasmevent.h"
26#if QT_CONFIG(draganddrop)
27#include "qwasmdrag.h"
28#endif
30
31#include <iostream>
32#include <sstream>
33
34#include <emscripten/val.h>
35
36#include <QtCore/private/qstdweb_p.h>
37#include <QKeySequence>
38
40
42
43QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
44 QWasmCompositor *compositor, QWasmBackingStore *backingStore,
45 WId nativeHandle)
47 m_compositor(compositor),
48 m_backingStore(backingStore),
49 m_deadKeySupport(deadKeySupport),
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 // Hide the canvas from screen readers.
126 m_canvas.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
127 m_window.call<void>("appendChild", m_canvas);
128
129 m_a11yContainer["classList"].call<void>("add", emscripten::val("qt-window-a11y-container"));
130 m_window.call<void>("appendChild", m_a11yContainer);
131
132 if (QWasmAccessibility::isEnabled())
134
135 const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
136 if (rendersTo2dContext)
137 m_context2d = m_canvas.call<emscripten::val>("getContext", emscripten::val("2d"));
138
139 m_winId = WId(&m_window);
140 m_decoratedWindow.set("id", "qt-window-" + std::to_string(m_winId));
141 emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas);
142
143 m_flags = window()->flags();
144
146
147 m_transientWindowChangedConnection =
148 QObject::connect(
149 window(), &QWindow::transientParentChanged,
150 window(), [this](QWindow *tp) { onTransientParentChanged(tp); });
151
152 m_modalityChangedConnection =
153 QObject::connect(
154 window(), &QWindow::modalityChanged,
155 window(), [this](Qt::WindowModality) { onModalityChanged(); });
156
157 setParent(parent());
158}
159
161{
162 m_pointerDownCallback = QWasmEventHandler(m_window, "pointerdown",
163 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); }
164 );
165 m_pointerMoveCallback = QWasmEventHandler(m_window, "pointermove",
166 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); }
167 );
168 m_pointerUpCallback = QWasmEventHandler(m_window, "pointerup",
169 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); }
170 );
171 m_pointerCancelCallback = QWasmEventHandler(m_window, "pointercancel",
172 [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); }
173 );
174 m_pointerEnterCallback = QWasmEventHandler(m_window, "pointerenter",
175 [this](emscripten::val event) { this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); }
176 );
177 m_pointerLeaveCallback = QWasmEventHandler(m_window, "pointerleave",
178 [this](emscripten::val event) { this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); }
179 );
180
181#if QT_CONFIG(draganddrop)
182 m_window.call<void>("setAttribute", emscripten::val("draggable"), emscripten::val("true"));
183 m_dragStartCallback = QWasmEventHandler(m_window, "dragstart",
184 [this](emscripten::val event) {
185 DragEvent dragEvent(EventType::DragStart, event, window());
186 QWasmDrag::instance()->onNativeDragStarted(&dragEvent);
187 }
188 );
189 m_dragOverCallback = QWasmEventHandler(m_window, "dragover",
190 [this](emscripten::val event) {
191 DragEvent dragEvent(EventType::DragOver, event, window());
192 QWasmDrag::instance()->onNativeDragOver(&dragEvent);
193 }
194 );
195 m_dropCallback = QWasmEventHandler(m_window, "drop",
196 [this](emscripten::val event) {
197 DragEvent dragEvent(EventType::Drop, event, window());
198 QWasmDrag::instance()->onNativeDrop(&dragEvent);
199 }
200 );
201 m_dragEndCallback = QWasmEventHandler(m_window, "dragend",
202 [this](emscripten::val event) {
203 DragEvent dragEvent(EventType::DragEnd, event, window());
204 QWasmDrag::instance()->onNativeDragFinished(&dragEvent);
205 }
206 );
207 m_dragLeaveCallback = QWasmEventHandler(m_window, "dragleave",
208 [this](emscripten::val event) {
209 DragEvent dragEvent(EventType::DragLeave, event, window());
210 QWasmDrag::instance()->onNativeDragLeave(&dragEvent);
211 }
212 );
213#endif // QT_CONFIG(draganddrop)
214
215 m_wheelEventCallback = QWasmEventHandler(m_window, "wheel",
216 [this](emscripten::val event) { this->handleWheelEvent(event); });
217
218 m_keyDownCallback = QWasmEventHandler(m_window, "keydown",
219 [this](emscripten::val event) { this->handleKeyEvent(KeyEvent(EventType::KeyDown, event, m_deadKeySupport)); });
220 m_keyUpCallback =QWasmEventHandler(m_window, "keyup",
221 [this](emscripten::val event) {this->handleKeyEvent(KeyEvent(EventType::KeyUp, event, m_deadKeySupport)); });
222
223 m_inputCallback = QWasmEventHandler(m_window, "input",
224 [this](emscripten::val event){ handleInputEvent(event); });
225 m_compositionUpdateCallback = QWasmEventHandler(m_window, "compositionupdate",
226 [this](emscripten::val event){ handleCompositionUpdateEvent(event); });
227 m_compositionStartCallback = QWasmEventHandler(m_window, "compositionstart",
228 [this](emscripten::val event){ handleCompositionStartEvent(event); });
229 m_compositionEndCallback = QWasmEventHandler(m_window, "compositionend",
230 [this](emscripten::val event){ handleCompositionEndEvent(event); });
231 m_beforeInputCallback = QWasmEventHandler(m_window, "beforeinput",
232 [this](emscripten::val event){ handleBeforeInputEvent(event); });
233 }
234
236{
238
239#if QT_CONFIG(accessibility)
240 QWasmAccessibility::onRemoveWindow(window());
241#endif
242 QObject::disconnect(m_transientWindowChangedConnection);
243 QObject::disconnect(m_modalityChangedConnection);
244
245 shutdown();
246
247 emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector());
248 m_window.call<void>("removeChild", m_canvas);
249 m_window.call<void>("removeChild", m_a11yContainer);
250 m_context2d = emscripten::val::undefined();
251 commitParent(nullptr);
252 if (m_requestAnimationFrameId > -1)
253 emscripten_cancel_animation_frame(m_requestAnimationFrameId);
254}
255
256void QWasmWindow::shutdown()
257{
258 if (!window() ||
259 (QGuiApplication::focusWindow() && // Don't act if we have a focus window different from this
260 QGuiApplication::focusWindow() != window()))
261 return;
262
263 // Make a list of all windows sorted on active index.
264 // Skip windows with active index 0 as they have
265 // never been active.
266 std::map<uint64_t, QWasmWindow *> allWindows;
267 for (const auto &w : platformScreen()->allWindows()) {
268 if (w->getActiveIndex() > 0)
269 allWindows.insert({w->getActiveIndex(), w});
270 }
271
272 // window is not in all windows
273 if (getActiveIndex() > 0)
274 allWindows.insert({getActiveIndex(), this});
275
276 if (allWindows.size() >= 2) {
277 const auto lastIt = std::prev(allWindows.end());
278 const auto prevIt = std::prev(lastIt);
279 const auto lastW = lastIt->second;
280 const auto prevW = prevIt->second;
281
282 if (lastW == this) // Only act if window is last to be active
283 prevW->requestActivateWindow();
284 }
285}
286
288{
289 return window()->requestedFormat();
290}
291
292QWasmWindow *QWasmWindow::fromWindow(const QWindow *window)
293{
294 if (!window ||!window->handle())
295 return nullptr;
296 return static_cast<QWasmWindow *>(window->handle());
297}
298
300{
301 if (!window())
302 return nullptr;
303
304 return fromWindow(window()->transientParent());
305}
306
308{
309 return window()->flags();
310}
311
312bool QWasmWindow::isModal() const
313{
314 return window()->isModal();
315}
316
318{
319 window()->setWindowState(Qt::WindowNoState);
320}
321
323{
324 window()->setWindowState(Qt::WindowMaximized);
325}
326
328{
329 window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
330 : Qt::WindowMaximized);
331}
332
334{
335 window()->close();
336}
337
339{
341 QGuiApplicationPrivate::instance()->closeAllPopups();
342}
343
345{
346 QPointF pointInScreen = platformScreen()->mapFromLocal(
347 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
348 return QWindowSystemInterface::handleMouseEvent(
349 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
350 pointInScreen, event.mouseButtons, event.mouseButton,
351 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
352 event.modifiers);
353}
354
356{
357 auto initialGeometry = QPlatformWindow::initialGeometry(window(),
358 windowGeometry(), defaultWindowSize, defaultWindowSize);
359 m_normalGeometry = initialGeometry;
360
361 setWindowState(window()->windowStates());
362 setWindowFlags(window()->flags());
363 setWindowTitle(window()->title());
364 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
365
366 if (window()->isTopLevel())
367 setWindowIcon(window()->icon());
368 QPlatformWindow::setGeometry(m_normalGeometry);
369
370#if QT_CONFIG(accessibility)
371 // Add accessibility-enable button. The user can activate this
372 // button to opt-in to accessibility.
373 if (window()->isTopLevel())
374 QWasmAccessibility::addAccessibilityEnableButton(window());
375#endif
376}
377
379{
380 return static_cast<QWasmScreen *>(window()->screen()->handle());
381}
382
384{
385 if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
386 return;
387
388 auto image = m_backingStore->getUpdatedWebImage(this);
389 if (image.isUndefined())
390 return;
391 m_context2d.call<void>("putImageData", image, emscripten::val(0), emscripten::val(0));
392}
393
395{
396 m_decoratedWindow["style"].set("zIndex", std::to_string(z));
397}
398
399void QWasmWindow::setWindowCursor(QByteArray cssCursorName)
400{
401 m_window["style"].set("cursor", emscripten::val(cssCursorName.constData()));
402}
403
404void QWasmWindow::setGeometry(const QRect &rect)
405{
406 const auto margins = frameMargins();
407
408 const QRect clientAreaRect = ([this, &rect, &margins]() {
409 if (m_state.testFlag(Qt::WindowFullScreen))
410 return platformScreen()->geometry();
411 if (m_state.testFlag(Qt::WindowMaximized))
412 return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
413
414 auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
415
416 // In viewport
417 auto containerGeometryInViewport =
418 QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
419 "getBoundingClientRect"))
420 .toRect();
421
422 auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
423
424 QRect cappedGeometry(rectInViewport);
425 if (!parent()) {
426 // Clamp top level windows top position to the screen bounds
427 cappedGeometry.moveTop(
428 std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
429 containerGeometryInViewport.y() + margins.top()));
430 }
431 cappedGeometry.setSize(
432 cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
433 return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
434 rect.size());
435 })();
436 m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
437
438 const auto frameRect =
439 clientAreaRect
440 .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
441 .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
442
443 m_decoratedWindow["style"].set("left", std::to_string(frameRect.left()) + "px");
444 m_decoratedWindow["style"].set("top", std::to_string(frameRect.top()) + "px");
445 m_canvas["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
446 m_canvas["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
447 m_a11yContainer["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
448 m_a11yContainer["style"].set("height", std::to_string(clientAreaRect.height()) + "px");
449
450 // Important for the title flexbox to shrink correctly
451 m_window["style"].set("width", std::to_string(clientAreaRect.width()) + "px");
452
453 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
454
455 m_canvas.set("width", canvasSize.width());
456 m_canvas.set("height", canvasSize.height());
457
458 bool shouldInvalidate = true;
459 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
460 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
461 m_normalGeometry = clientAreaRect;
462 }
463
464 QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
465 if (wasmInput && (QGuiApplication::focusWindow() == window()))
466 wasmInput->updateGeometry();
467
468 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
469 if (shouldInvalidate)
470 invalidate();
471 else
472 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()));
473}
474
475void QWasmWindow::setVisible(bool visible)
476{
477 // TODO(mikolajboc): isVisible()?
478 const bool nowVisible = m_decoratedWindow["style"]["display"].as<std::string>() == "block";
479 if (visible == nowVisible)
480 return;
481
482 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::ExposeEventDelivery);
483 m_decoratedWindow["style"].set("display", visible ? "block" : "none");
484 if (window() == QGuiApplication::focusWindow())
485 focus();
486
487 if (visible) {
488 applyWindowState();
489#if QT_CONFIG(accessibility)
490 QWasmAccessibility::onShowWindow(window());
491#endif
492 }
493}
494
496{
497 return window()->isVisible();
498}
499
501{
502 const auto frameRect =
503 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>("getBoundingClientRect"));
504 const auto canvasRect =
505 QRectF::fromDOMRect(m_window.call<emscripten::val>("getBoundingClientRect"));
506 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
507 frameRect.right() - canvasRect.right(),
508 frameRect.bottom() - canvasRect.bottom())
509 .toMargins();
510}
511
513{
514 bringToTop();
515 invalidate();
516}
517
519{
520 sendToBottom();
521 invalidate();
522}
523
525{
526 return m_winId;
527}
528
530{
531 // setGeometry() will take care of minimum and maximum size constraints
532 setGeometry(windowGeometry());
533 m_nonClientArea->propagateSizeHints();
534}
535
536void QWasmWindow::setOpacity(qreal level)
537{
538 m_decoratedWindow["style"].set("opacity", qBound(0.0, level, 1.0));
539}
540
541void QWasmWindow::invalidate()
542{
543 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()));
544}
545
547{
548 dom::syncCSSClassWith(m_decoratedWindow, "inactive", !active);
549}
550
551void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
552{
553 flags = fixTopLevelWindowFlags(flags);
554
555 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
556 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
557 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
558 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
559 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
560 }
561 m_flags = flags;
562 dom::syncCSSClassWith(m_decoratedWindow, "frameless", !hasFrame() || !window()->isTopLevel());
563 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
564 dom::syncCSSClassWith(m_decoratedWindow, "has-shadow", hasShadow());
565 dom::syncCSSClassWith(m_decoratedWindow, "has-title", hasTitleBar());
566 dom::syncCSSClassWith(m_decoratedWindow, "transparent-for-input",
567 flags.testFlag(Qt::WindowTransparentForInput));
568
569 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
570 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
571}
572
573void QWasmWindow::setWindowState(Qt::WindowStates newState)
574{
575 // Child windows can not have window states other than Qt::WindowActive
576 if (parent())
577 newState &= Qt::WindowActive;
578
579 const Qt::WindowStates oldState = m_state;
580
581 if (newState.testFlag(Qt::WindowMinimized)) {
582 newState.setFlag(Qt::WindowMinimized, false);
583 qWarning("Qt::WindowMinimized is not implemented in wasm");
584 window()->setWindowStates(newState);
585 return;
586 }
587
588 if (newState == oldState)
589 return;
590
591 m_state = newState;
592 m_previousWindowState = oldState;
593
594 applyWindowState();
595}
596
597void QWasmWindow::setWindowTitle(const QString &title)
598{
599 m_nonClientArea->titleBar()->setTitle(title);
600}
601
602void QWasmWindow::setWindowIcon(const QIcon &icon)
603{
604 const auto dpi = screen()->devicePixelRatio();
605 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
606 if (pixmap.isNull()) {
607 m_nonClientArea->titleBar()->setIcon(
608 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo), "svg+xml");
609 return;
610 }
611
612 QByteArray bytes;
613 QBuffer buffer(&bytes);
614 pixmap.save(&buffer, "png");
615 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(), "png");
616}
617
618void QWasmWindow::applyWindowState()
619{
620 QRect newGeom;
621
622 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
623 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
624 if (isFullscreen)
625 newGeom = platformScreen()->geometry();
626 else if (isMaximized)
627 newGeom = platformScreen()->availableGeometry().marginsRemoved(frameMargins());
628 else
629 newGeom = normalGeometry();
630
631 dom::syncCSSClassWith(m_decoratedWindow, "has-border", hasBorder());
632 dom::syncCSSClassWith(m_decoratedWindow, "maximized", isMaximized);
633
634 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
635 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
636
637 if (isVisible())
638 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
639 setGeometry(newGeom);
640}
641
642void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
643{
644 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
645 m_commitedParent = parent;
646}
647
648void QWasmWindow::handleKeyEvent(const KeyEvent &event)
649{
650 qCDebug(qLcQpaWasmInputContext) << "handleKeyEvent";
651
652 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) {
653 handleKeyForInputContextEvent(event);
654 } else {
655 if (processKey(event)) {
656 event.webEvent.call<void>("preventDefault");
657 event.webEvent.call<void>("stopPropagation");
658 }
659 }
660}
661
662bool QWasmWindow::processKey(const KeyEvent &event)
663{
664 constexpr bool ProceedToNativeEvent = false;
665 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
666
667#if QT_CONFIG(clipboard)
668 const auto clipboardResult =
669 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
670
671 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
672 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
673 return ProceedToNativeEvent;
674#endif
675
676 const auto result = QWindowSystemInterface::handleKeyEvent(
677 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
678 event.modifiers, event.text, event.autoRepeat);
679
680#if QT_CONFIG(clipboard)
681 return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
682 ? ProceedToNativeEvent
683 : result;
684#else
685 return result;
686#endif
687}
688
689void QWasmWindow::handleKeyForInputContextEvent(const KeyEvent &keyEvent)
690{
691 //
692 // Things to consider:
693 //
694 // (Alt + '̃~') + a -> compose('~', 'a')
695 // (Compose) + '\'' + e -> compose('\'', 'e')
696 // complex (i.e Chinese et al) input handling
697 // Multiline text edit backspace at start of line
698 //
699 emscripten::val event = keyEvent.webEvent;
700 bool useInputContext = [event]() -> bool {
701 const QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
702 if (!wasmInput)
703 return false;
704
705 const auto keyString = QString::fromStdString(event["key"].as<std::string>());
706 qCDebug(qLcQpaWasmInputContext) << "Key callback" << keyString << keyString.size();
707
708 // Events with isComposing set are handled by the input context
709 bool composing = event["isComposing"].as<bool>();
710
711 // Android makes a bunch of KeyEvents as "Unidentified",
712 // make inputContext handle those.
713 bool androidUnidentified = (keyString == "Unidentified");
714
715 // Not all platforms use 'isComposing' for '~' + 'a', in this
716 // case send the key with state ('ctrl', 'alt', or 'meta') to
717 // processKeyForInputContext
718 bool hasModifiers = event["ctrlKey"].as<bool>()
719 || event["altKey"].as<bool>()
720 || event["metaKey"].as<bool>();
721
722 // This is like; 'Shift','ArrowRight','AltGraph', ...
723 // send all of these to processKeyForInputContext
724 bool hasNoncharacterKeyString = keyString.size() != 1;
725
726 bool overrideCompose = !hasModifiers && !hasNoncharacterKeyString && wasmInput->inputMethodAccepted();
727 return composing || androidUnidentified || overrideCompose;
728 }();
729
730 if (!useInputContext) {
731 qCDebug(qLcQpaWasmInputContext) << "processKey as KeyEvent";
732 if (processKeyForInputContext(keyEvent))
733 event.call<void>("preventDefault");
734 event.call<void>("stopImmediatePropagation");
735 }
736}
737
738bool QWasmWindow::processKeyForInputContext(const KeyEvent &event)
739{
740 qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
741 Q_ASSERT(event.type == EventType::KeyDown || event.type == EventType::KeyUp);
742
743 QKeySequence keySeq(event.modifiers | event.key);
744
745 if (keySeq == QKeySequence::Paste) {
746 // Process it in pasteCallback and inputCallback
747 return false;
748 }
749
750 const auto result = QWindowSystemInterface::handleKeyEvent(
751 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
752 event.modifiers, event.text);
753
754#if QT_CONFIG(clipboard)
755 // Copy/Cut callback required to copy qtClipboard to system clipboard
756 if (keySeq == QKeySequence::Copy || keySeq == QKeySequence::Cut)
757 return false;
758#endif
759
760 return result;
761}
762
763void QWasmWindow::handleInputEvent(emscripten::val event)
764{
765 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
766 inputContext->inputCallback(event);
767 else
768 m_focusHelper.set("innerHTML", std::string());
769}
770
771void QWasmWindow::handleCompositionStartEvent(emscripten::val event)
772{
773 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
774 inputContext->compositionStartCallback(event);
775 else
776 m_focusHelper.set("innerHTML", std::string());
777}
778
779void QWasmWindow::handleCompositionUpdateEvent(emscripten::val event)
780{
781 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
782 inputContext->compositionUpdateCallback(event);
783 else
784 m_focusHelper.set("innerHTML", std::string());
785}
786
787void QWasmWindow::handleCompositionEndEvent(emscripten::val event)
788{
789 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
790 inputContext->compositionEndCallback(event);
791 else
792 m_focusHelper.set("innerHTML", std::string());
793}
794
795void QWasmWindow::handleBeforeInputEvent(emscripten::val event)
796{
797 qWarning() << Q_FUNC_INFO;
798
799 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
800 inputContext->beforeInputCallback(event);
801 // else
802 // m_focusHelper.set("innerHTML", std::string());
803}
804
805void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event)
806{
807 if (processPointerEnterLeave(event))
808 event.webEvent.call<void>("preventDefault");
809}
810
811bool QWasmWindow::processPointerEnterLeave(const PointerEvent &event)
812{
814 return false;
815
816 switch (event.type) {
818 const auto pointInScreen = platformScreen()->mapFromLocal(
819 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
820 QWindowSystemInterface::handleEnterEvent(
821 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
822 break;
823 }
826 break;
827 default:
828 break;
829 }
830
831 return false;
832}
833
834void QWasmWindow::processPointer(const PointerEvent &event)
835{
836 switch (event.type) {
837 case EventType::PointerDown:
838 if (event.isTargetedForQtElement())
839 m_window.call<void>("setPointerCapture", event.pointerId);
840
841 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
842 != Qt::WindowDoesNotAcceptFocus
843 && window()->isTopLevel())
844 window()->requestActivate();
845 break;
846 case EventType::PointerUp:
847 if (event.isTargetedForQtElement())
848 m_window.call<void>("releasePointerCapture", event.pointerId);
849 break;
850 default:
851 break;
852 };
853
854 const bool eventAccepted = deliverPointerEvent(event);
855 if (!eventAccepted && event.type == EventType::PointerDown)
856 QGuiApplicationPrivate::instance()->closeAllPopups();
857
858 if (eventAccepted) {
859 event.webEvent.call<void>("preventDefault");
860 event.webEvent.call<void>("stopPropagation");
861 }
862}
863
864bool QWasmWindow::deliverPointerEvent(const PointerEvent &event)
865{
866 const auto pointInScreen = platformScreen()->mapFromLocal(
867 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
868
869 const auto geometryF = platformScreen()->geometry().toRectF();
870 const QPointF targetPointClippedToScreen(
871 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
872 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
873
874 if (event.pointerType == PointerType::Mouse) {
875 const QEvent::Type eventType =
876 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client);
877
878 return eventType != QEvent::None
879 && QWindowSystemInterface::handleMouseEvent(
880 window(), QWasmIntegration::getTimestamp(),
881 window()->mapFromGlobal(targetPointClippedToScreen),
882 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
883 eventType, event.modifiers);
884 }
885
886 if (event.pointerType == PointerType::Pen) {
887 qreal pressure;
888 switch (event.type) {
891 pressure = event.pressure;
892 break;
894 pressure = 0.0;
895 break;
896 default:
897 return false;
898 }
899 // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
900 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
901 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
902 // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
903 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
904 return QWindowSystemInterface::handleTabletEvent(
905 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
906 window()->mapFromGlobal(targetPointClippedToScreen),
907 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
908 event.tangentialPressure, rotation, event.modifiers);
909 }
910
911 QWindowSystemInterface::TouchPoint *touchPoint;
912
913 QPointF pointInTargetWindowCoords =
914 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
915 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
916 pointInTargetWindowCoords.y() / window()->height());
917
918 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
919 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
920 touchPoint = &tp.value();
921 } else {
922 touchPoint = &m_pointerIdToTouchPoints
923 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
924 .value();
925
926 // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent()
927 // will not synthesize mouse events for touch points with negative id; use the absolute value for
928 // the touch point id.
929 touchPoint->id = qAbs(event.pointerId);
930
931 touchPoint->state = QEventPoint::State::Pressed;
932 }
933
934 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
935 touchPoint->normalPosition = normalPosition;
936 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
937 .translated(-event.width / 2, -event.height / 2);
938 touchPoint->pressure = event.pressure;
939
940 switch (event.type) {
941 case EventType::PointerUp:
942 touchPoint->state = QEventPoint::State::Released;
943 break;
944 case EventType::PointerMove:
945 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
946 : QEventPoint::State::Updated);
947 break;
948 default:
949 break;
950 }
951
952 QList<QWindowSystemInterface::TouchPoint> touchPointList;
953 touchPointList.reserve(m_pointerIdToTouchPoints.size());
954 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
955 std::back_inserter(touchPointList),
956 [](const QWindowSystemInterface::TouchPoint &val) { return val; });
957
958 if (event.type == EventType::PointerUp)
959 m_pointerIdToTouchPoints.remove(event.pointerId);
960
961 return event.type == EventType::PointerCancel
962 ? QWindowSystemInterface::handleTouchCancelEvent(
963 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
964 event.modifiers)
965 : QWindowSystemInterface::handleTouchEvent(
966 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
967 touchPointList, event.modifiers);
968}
969
970void QWasmWindow::handleWheelEvent(const emscripten::val &event)
971{
972 if (processWheel(WheelEvent(EventType::Wheel, event)))
973 event.call<void>("preventDefault");
974}
975
976bool QWasmWindow::processWheel(const WheelEvent &event)
977{
978 // Web scroll deltas are inverted from Qt deltas - negate.
979 const int scrollFactor = -([&event]() {
980 switch (event.deltaMode) {
981 case DeltaMode::Pixel:
982 return 1;
983 case DeltaMode::Line:
984 return 12;
985 case DeltaMode::Page:
986 return 20;
987 };
988 })();
989
990 const auto pointInScreen = platformScreen()->mapFromLocal(
991 dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
992
993 return QWindowSystemInterface::handleWheelEvent(
994 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
995 pointInScreen, (event.delta * scrollFactor).toPoint(),
996 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
997 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
998}
999
1000// Fix top level window flags in case only the type flags are passed.
1001Qt::WindowFlags QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags) const
1002{
1003 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
1004 if (flags.testFlag(Qt::Window)) {
1005 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1006 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
1007 }
1008 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
1009 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1010
1011 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1012 flags |= Qt::FramelessWindowHint;
1013 }
1014 return flags;
1015}
1016
1017bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
1018{
1019 if (!transientParent())
1020 return false;
1021
1022 if (isModal())
1023 return true;
1024
1025 if (flags.testFlag(Qt::Tool) ||
1026 flags.testFlag(Qt::SplashScreen) ||
1027 flags.testFlag(Qt::ToolTip) ||
1028 flags.testFlag(Qt::Popup))
1029 {
1030 return true;
1031 }
1032
1033 return false;
1034}
1035
1036QWasmWindowStack<>::PositionPreference QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags) const
1037{
1038 flags = fixTopLevelWindowFlags(flags);
1039
1040 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1041 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1042 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1043 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1044 if (shouldBeAboveTransientParentFlags(flags))
1045 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1046 return QWasmWindowStack<>::PositionPreference::Regular;
1047}
1048
1050{
1051 return m_normalGeometry;
1052}
1053
1055{
1056 return screen()->devicePixelRatio();
1057}
1058
1060{
1061 m_compositor->requestUpdateWindow(this, QRect(QPoint(0, 0), geometry().size()), QWasmCompositor::UpdateRequestDelivery);
1062}
1063
1064bool QWasmWindow::hasFrame() const
1065{
1066 return !m_flags.testFlag(Qt::FramelessWindowHint);
1067}
1068
1069bool QWasmWindow::hasBorder() const
1070{
1071 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1072 && !windowIsPopupType(m_flags) && !parent();
1073}
1074
1075bool QWasmWindow::hasTitleBar() const
1076{
1077 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1078}
1079
1080bool QWasmWindow::hasShadow() const
1081{
1082 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1083}
1084
1085bool QWasmWindow::hasMaximizeButton() const
1086{
1087 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1088}
1089
1090bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags) const
1091{
1092 if (flags.testFlag(Qt::Tool))
1093 return false; // Qt::Tool has the Popup bit set but isn't an actual Popup window
1094
1095 return (flags.testFlag(Qt::Popup));
1096}
1097
1099{
1100 QWindow *modalWindow;
1101 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1102 static_cast<QWasmWindow *>(modalWindow->handle())->requestActivateWindow();
1103 return;
1104 }
1105
1106 raise();
1107 setAsActiveNode();
1108
1109 if (!QWasmIntegration::get()->inputContext())
1110 focus();
1111 QPlatformWindow::requestActivateWindow();
1112}
1113
1115{
1116 if (QWasmAccessibility::isEnabled())
1117 return;
1118
1119 m_focusHelper.call<void>("focus");
1120}
1121
1123{
1124 m_focusHelper.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1125 m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
1126}
1127
1129{
1130 Q_UNUSED(grab);
1131 return false;
1132}
1133
1134bool QWasmWindow::windowEvent(QEvent *event)
1135{
1136 switch (event->type()) {
1137 case QEvent::WindowBlocked:
1138 m_decoratedWindow["classList"].call<void>("add", emscripten::val("blocked"));
1139 return false; // Propagate further
1140 case QEvent::WindowUnblocked:;
1141 m_decoratedWindow["classList"].call<void>("remove", emscripten::val("blocked"));
1142 return false; // Propagate further
1143 default:
1144 return QPlatformWindow::windowEvent(event);
1145 }
1146}
1147
1148void QWasmWindow::setMask(const QRegion &region)
1149{
1150 if (region.isEmpty()) {
1151 m_decoratedWindow["style"].set("clipPath", emscripten::val(""));
1152 return;
1153 }
1154
1155 std::ostringstream cssClipPath;
1156 cssClipPath << "path('";
1157 for (const auto &rect : region) {
1158 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1159 cssClipPath << "M " << cssRect.left() << " " << cssRect.top() << " ";
1160 cssClipPath << "L " << cssRect.right() << " " << cssRect.top() << " ";
1161 cssClipPath << "L " << cssRect.right() << " " << cssRect.bottom() << " ";
1162 cssClipPath << "L " << cssRect.left() << " " << cssRect.bottom() << " z ";
1163 }
1164 cssClipPath << "')";
1165 m_decoratedWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
1166}
1167
1168void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1169{
1170 Q_UNUSED(newTransientParent);
1171
1172 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1173 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1174 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1175}
1176
1178{
1179 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1180 QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
1181 QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
1182}
1183
1184void QWasmWindow::setParent(const QPlatformWindow *)
1185{
1186 // The window flags depend on whether we are a
1187 // child window or not, so update them here.
1188 setWindowFlags(window()->flags());
1189
1190 commitParent(parentNode());
1191}
1192
1194{
1195 return "!qtwindow" + std::to_string(m_winId);
1196}
1197
1199{
1200 return m_window;
1201}
1202
1204{
1205 if (parent())
1206 return static_cast<QWasmWindow *>(parent());
1207 return platformScreen();
1208}
1209
1211{
1212 return this;
1213}
1214
1215void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
1216 QWasmWindowStack<>::PositionPreference positionPreference)
1217{
1218 if (previous)
1219 previous->containerElement().call<void>("removeChild", m_decoratedWindow);
1220 if (current)
1221 current->containerElement().call<void>("appendChild", m_decoratedWindow);
1222 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
1223}
1224
1225QT_END_NAMESPACE
QRect window() const
Returns the window rectangle.
QWasmCompositor(QWasmScreen *screen)
static QWasmIntegration * get()
static void destroyWebGLContext(QPlatformSurface *surface)
emscripten::val element() const
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
void setVisible(bool visible) override
Reimplemented in subclasses to show the surface if visible is true, and hide it if visible is false.
qreal devicePixelRatio() const override
Reimplement this function in subclass to return the device pixel ratio for the window.
QRect normalGeometry() const override
Returns the geometry of a window in 'normal' state (neither maximized, fullscreen nor minimized) for ...
QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, QWasmCompositor *compositor, QWasmBackingStore *backingStore, WId nativeHandle)
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
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.
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:113
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)
DeltaMode
Definition qwasmevent.h:53
PointerType
Definition qwasmevent.h:41
EventType
Definition qwasmevent.h:24
WindowArea
Definition qwasmevent.h:48
EventType type
Definition qwasmevent.h:62
PointerType pointerType
Definition qwasmevent.h:128
DeltaMode deltaMode
Definition qwasmevent.h:157