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