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