5#include <qpa/qwindowsysteminterface.h>
6#include <private/qguiapplication_p.h>
7#include <QtCore/qfile.h>
8#include <QtGui/private/qwindow_p.h>
9#include <QtGui/private/qhighdpiscaling_p.h>
10#include <private/qpixmapcache_p.h>
11#include <QtGui/qopenglfunctions.h>
16#if QT_CONFIG(clipboard)
17#include "qwasmclipboard.h"
27#if QT_CONFIG(draganddrop)
35#include <emscripten/val.h>
37#include <QtCore/private/qstdweb_p.h>
38#include <QKeySequence>
48 m_compositor(compositor),
49 m_backingStore(backingStore),
59 m_decoratedWindow.set(
"className",
"qt-decorated-window");
60 m_decoratedWindow[
"style"].set(
"display", std::string(
"none"));
62 m_nonClientArea = std::make_unique<NonClientArea>(
this, m_decoratedWindow);
63 m_nonClientArea->titleBar()->setTitle(window()->title());
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);
81 m_window.set(
"className",
"qt-window");
82 m_decoratedWindow.call<
void>(
"appendChild", m_window);
84 m_canvas[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-canvas"));
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);
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);
112 m_inputElement[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-input-element"));
113 m_inputElement.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
114 m_inputElement.set(
"type",
"text");
115 m_inputElement[
"style"].set(
"position",
"absolute");
116 m_inputElement[
"style"].set(
"left", 0);
117 m_inputElement[
"style"].set(
"top", 0);
118 m_inputElement[
"style"].set(
"width",
"1px");
119 m_inputElement[
"style"].set(
"height",
"1px");
120 m_inputElement[
"style"].set(
"z-index", -2);
121 m_inputElement[
"style"].set(
"opacity", 0);
122 m_inputElement[
"style"].set(
"display",
"");
123 m_window.call<
void>(
"appendChild", m_inputElement);
126 m_canvas.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
127 m_canvas[
"style"].set(
"pointerEvents",
"none");
129 m_window.call<
void>(
"appendChild", m_canvas);
131 m_a11yContainer[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-a11y-container"));
132 m_window.call<
void>(
"appendChild", m_a11yContainer);
134 if (QWasmAccessibility::isEnabled())
137 const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
138 if (rendersTo2dContext)
139 m_context2d = m_canvas.call<emscripten::val>(
"getContext", emscripten::val(
"2d"));
141 m_winId = WId(&m_window);
142 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
143 emscripten::val::module_property(
"specialHTMLTargets").set(canvasSelector(), m_canvas);
145 m_flags = window()->flags();
149 m_transientWindowChangedConnection =
151 window(), &QWindow::transientParentChanged,
152 window(), [
this](QWindow *tp) { onTransientParentChanged(tp); });
154 m_modalityChangedConnection =
156 window(), &QWindow::modalityChanged,
157 window(), [
this](Qt::WindowModality) { onModalityChanged(); });
164 m_pointerDownCallback = QWasmEventHandler(m_window,
"pointerdown",
165 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); }
167 m_pointerMoveCallback = QWasmEventHandler(m_window,
"pointermove",
168 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); }
170 m_pointerUpCallback = QWasmEventHandler(m_window,
"pointerup",
171 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); }
173 m_pointerCancelCallback = QWasmEventHandler(m_window,
"pointercancel",
174 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); }
176 m_pointerEnterCallback = QWasmEventHandler(m_window,
"pointerenter",
177 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); }
179 m_pointerLeaveCallback = QWasmEventHandler(m_window,
"pointerleave",
180 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); }
183#if QT_CONFIG(draganddrop)
184 m_window.call<
void>(
"setAttribute", emscripten::val(
"draggable"), emscripten::val(
"true"));
185 m_dragStartCallback = QWasmEventHandler(m_window,
"dragstart",
186 [
this](emscripten::val event) {
187 DragEvent dragEvent(EventType::DragStart, event, window());
188 QWasmDrag::instance()->onNativeDragStarted(&dragEvent);
191 m_dragOverCallback = QWasmEventHandler(m_window,
"dragover",
192 [
this](emscripten::val event) {
193 DragEvent dragEvent(EventType::DragOver, event, window());
194 QWasmDrag::instance()->onNativeDragOver(&dragEvent);
197 m_dropCallback = QWasmEventHandler(m_window,
"drop",
198 [
this](emscripten::val event) {
199 DragEvent dragEvent(EventType::Drop, event, window());
200 QWasmDrag::instance()->onNativeDrop(&dragEvent);
203 m_dragEndCallback = QWasmEventHandler(m_window,
"dragend",
204 [
this](emscripten::val event) {
205 DragEvent dragEvent(EventType::DragEnd, event, window());
206 QWasmDrag::instance()->onNativeDragFinished(&dragEvent, platformScreen());
207 releasePointerGrab(dragEvent);
210 m_dragEnterCallback = QWasmEventHandler(m_window,
"dragenter",
211 [
this](emscripten::val event) {
212 DragEvent dragEvent(EventType::DragEnter, event, window());
213 QWasmDrag::instance()->onNativeDragEnter(&dragEvent);
216 m_dragLeaveCallback = QWasmEventHandler(m_window,
"dragleave",
217 [
this](emscripten::val event) {
218 DragEvent dragEvent(EventType::DragLeave, event, window());
219 QWasmDrag::instance()->onNativeDragLeave(&dragEvent);
224 m_wheelEventCallback = QWasmEventHandler(m_window,
"wheel",
225 [
this](emscripten::val event) {
this->handleWheelEvent(event); });
227 m_keyDownCallback = QWasmEventHandler(m_window,
"keydown",
228 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyDown, event)); });
229 m_keyUpCallback =QWasmEventHandler(m_window,
"keyup",
230 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyUp, event)); });
232 m_inputCallback = QWasmEventHandler(m_window,
"input",
233 [
this](emscripten::val event){ handleInputEvent(event); });
234 m_compositionUpdateCallback = QWasmEventHandler(m_window,
"compositionupdate",
235 [
this](emscripten::val event){ handleCompositionUpdateEvent(event); });
236 m_compositionStartCallback = QWasmEventHandler(m_window,
"compositionstart",
237 [
this](emscripten::val event){ handleCompositionStartEvent(event); });
238 m_compositionEndCallback = QWasmEventHandler(m_window,
"compositionend",
239 [
this](emscripten::val event){ handleCompositionEndEvent(event); });
240 m_beforeInputCallback = QWasmEventHandler(m_window,
"beforeinput",
241 [
this](emscripten::val event){ handleBeforeInputEvent(event); });
248#if QT_CONFIG(accessibility)
249 QWasmAccessibility::onRemoveWindow(window());
251 QObject::disconnect(m_transientWindowChangedConnection);
252 QObject::disconnect(m_modalityChangedConnection);
256 emscripten::val::module_property(
"specialHTMLTargets").delete_(canvasSelector());
257 m_window.call<
void>(
"removeChild", m_canvas);
258 m_window.call<
void>(
"removeChild", m_a11yContainer);
259 m_context2d = emscripten::val::undefined();
260 commitParent(
nullptr);
261 if (m_requestAnimationFrameId > -1)
262 emscripten_cancel_animation_frame(m_requestAnimationFrameId);
268 (QGuiApplication::focusWindow() &&
269 QGuiApplication::focusWindow() != window()))
275 std::map<uint64_t, QWasmWindow *> allWindows;
276 for (
const auto &w : platformScreen()->allWindows()) {
277 if (w->getActiveIndex() > 0)
278 allWindows.insert({w->getActiveIndex(), w});
282 if (getActiveIndex() > 0)
283 allWindows.insert({getActiveIndex(),
this});
285 if (allWindows.size() >= 2) {
286 const auto lastIt =
std::prev(allWindows.end());
287 const auto prevIt =
std::prev(lastIt);
288 const auto lastW = lastIt->second;
289 const auto prevW = prevIt->second;
292 prevW->requestActivateWindow();
298 return window()->requestedFormat();
303 if (!window ||!window->handle())
305 return static_cast<
QWasmWindow *>(window->handle());
318 return window()->flags();
323 return window()->isModal();
328 window()->setWindowState(Qt::WindowNoState);
333 window()->setWindowState(Qt::WindowMaximized);
338 window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
339 : Qt::WindowMaximized);
350 QGuiApplicationPrivate::instance()->closeAllPopups();
357 return QWindowSystemInterface::handleMouseEvent(
358 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
359 pointInScreen, event.mouseButtons, event.mouseButton,
360 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
366 auto initialGeometry = QPlatformWindow::initialGeometry(window(),
367 windowGeometry(), defaultWindowSize, defaultWindowSize);
368 m_normalGeometry = initialGeometry;
370 setWindowState(window()->windowStates());
371 setWindowFlags(window()->flags());
372 setWindowTitle(window()->title());
373 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
375 if (window()->isTopLevel())
376 setWindowIcon(window()->icon());
377 QPlatformWindow::setGeometry(m_normalGeometry);
379#if QT_CONFIG(accessibility)
382 if (window()->isTopLevel())
383 QWasmAccessibility::addAccessibilityEnableButton(window());
389 return static_cast<
QWasmScreen *>(window()->screen()->handle());
394 if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
397 auto image = m_backingStore->getUpdatedWebImage(
this);
398 if (image.isUndefined())
400 m_context2d.call<
void>(
"putImageData", image, emscripten::val(0), emscripten::val(0));
405 m_decoratedWindow[
"style"].set(
"zIndex", std::to_string(z));
410 m_window[
"style"].set(
"cursor", emscripten::val(cssCursorName.constData()));
415 const auto margins = frameMargins();
417 const QRect clientAreaRect = ([
this, &rect, &margins]() {
418 if (m_state.testFlag(Qt::WindowFullScreen))
419 return platformScreen()->geometry();
420 if (m_state.testFlag(Qt::WindowMaximized))
421 return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
423 auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
426 auto containerGeometryInViewport =
427 QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
428 "getBoundingClientRect"))
431 auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
433 QRect cappedGeometry(rectInViewport);
436 cappedGeometry.moveTop(
437 std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
438 containerGeometryInViewport.y() + margins.top()));
440 cappedGeometry.setSize(
441 cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
442 return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
445 m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
447 const auto frameRect =
449 .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
450 .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
452 m_decoratedWindow[
"style"].set(
"left", std::to_string(frameRect.left()) +
"px");
453 m_decoratedWindow[
"style"].set(
"top", std::to_string(frameRect.top()) +
"px");
454 m_canvas[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
455 m_canvas[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
456 m_a11yContainer[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
457 m_a11yContainer[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
460 m_window[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
461 m_window[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
463 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
465 m_canvas.set(
"width", canvasSize.width());
466 m_canvas.set(
"height", canvasSize.height());
468 bool shouldInvalidate =
true;
469 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
470 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
471 m_normalGeometry = clientAreaRect;
475 if (wasmInput && (QGuiApplication::focusWindow() == window()))
476 wasmInput->updateGeometry();
478 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
479 if (shouldInvalidate)
482 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
488 const bool nowVisible = m_decoratedWindow[
"style"][
"display"].as<std::string>() ==
"block";
489 if (visible == nowVisible)
493 m_decoratedWindow[
"style"].set(
"display", visible ?
"block" :
"none");
494 if (window() == QGuiApplication::focusWindow())
499#if QT_CONFIG(accessibility)
500 QWasmAccessibility::onShowWindow(window());
507 return window()->isVisible();
512 const auto frameRect =
513 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>(
"getBoundingClientRect"));
514 const auto canvasRect =
515 QRectF::fromDOMRect(m_window.call<emscripten::val>(
"getBoundingClientRect"));
516 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
517 frameRect.right() - canvasRect.right(),
518 frameRect.bottom() - canvasRect.bottom())
543 m_nonClientArea->propagateSizeHints();
548 m_decoratedWindow[
"style"].set(
"opacity", qBound(0.0, level, 1.0));
553 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
558 dom::syncCSSClassWith(m_decoratedWindow,
"inactive", !active);
563 flags = fixTopLevelWindowFlags(flags);
568 if (
std::find(childStack().begin(), childStack().end(),
this) != childStack().end()) {
569 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
570 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
571 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
572 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
573 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
577 dom::syncCSSClassWith(m_decoratedWindow,
"frameless", !hasFrame() || !window()->isTopLevel());
578 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
579 dom::syncCSSClassWith(m_decoratedWindow,
"has-shadow", hasShadow());
580 dom::syncCSSClassWith(m_decoratedWindow,
"has-title", hasTitleBar());
581 dom::syncCSSClassWith(m_decoratedWindow,
"transparent-for-input",
582 flags.testFlag(Qt::WindowTransparentForInput));
584 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
585 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
592 newState &= Qt::WindowActive;
594 const Qt::WindowStates oldState = m_state;
596 if (newState.testFlag(Qt::WindowMinimized)) {
597 newState.setFlag(Qt::WindowMinimized,
false);
598 qWarning(
"Qt::WindowMinimized is not implemented in wasm");
599 window()->setWindowStates(newState);
603 if (newState == oldState)
607 m_previousWindowState = oldState;
614 m_nonClientArea->titleBar()->setTitle(title);
619 const auto dpi = screen()->devicePixelRatio();
620 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
621 if (pixmap.isNull()) {
622 m_nonClientArea->titleBar()->setIcon(
623 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo),
"svg+xml");
628 QBuffer buffer(&bytes);
629 pixmap.save(&buffer,
"png");
630 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(),
"png");
637 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
638 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
649 else if (isMaximized)
650 newGeom =
platformScreen()->availableGeometry().marginsRemoved(frameMargins());
654 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
655 dom::syncCSSClassWith(m_decoratedWindow,
"maximized", isMaximized);
657 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
658 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
661 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
665void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
667 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
668 m_commitedParent = parent;
673 qCDebug(qLcQpaWasmInputContext) <<
"handleKeyEvent";
675 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) {
676 handleKeyForInputContextEvent(event);
678 if (processKey(event)) {
679 event.webEvent.call<
void>(
"preventDefault");
680 event.webEvent.call<
void>(
"stopPropagation");
687 constexpr bool ProceedToNativeEvent =
false;
690#if QT_CONFIG(clipboard)
691 const auto clipboardResult =
692 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
694 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
695 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
696 return ProceedToNativeEvent;
699 const auto result = QWindowSystemInterface::handleKeyEvent(
700 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
701 event.modifiers, event.text, event.autoRepeat);
703#if QT_CONFIG(clipboard)
704 return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
705 ? ProceedToNativeEvent
722 qCDebug(qLcQpaWasmInputContext) <<
"processKey as KeyEvent";
724 if (processKeyForInputContext(keyEvent)) {
729 event.call<
void>(
"stopImmediatePropagation");
734 qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
737 QKeySequence keySeq(event.modifiers | event.key);
739 if (keySeq == QKeySequence::Paste) {
744 const auto result = QWindowSystemInterface::handleKeyEvent(
745 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
746 event.modifiers, event.text);
748#if QT_CONFIG(clipboard)
750 if (keySeq == QKeySequence::Copy || keySeq == QKeySequence::Cut)
759 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
760 inputContext->inputCallback(event);
762 m_focusHelper.set(
"innerHTML", std::string());
767 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
768 inputContext->compositionStartCallback(event);
770 m_focusHelper.set(
"innerHTML", std::string());
775 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
776 inputContext->compositionUpdateCallback(event);
778 m_focusHelper.set(
"innerHTML", std::string());
783 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
784 inputContext->compositionEndCallback(event);
786 m_focusHelper.set(
"innerHTML", std::string());
791 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
792 inputContext->beforeInputCallback(event);
794 m_focusHelper.set(
"innerHTML", std::string());
799 if (processPointerEnterLeave(event))
800 event.webEvent.call<
void>(
"preventDefault");
808 switch (event.type) {
812 QWindowSystemInterface::handleEnterEvent(
813 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
830 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
831 m_window.call<
bool>(
"hasPointerCapture", *m_capturedPointerId)) {
832 m_window.call<
void>(
"releasePointerCapture", *m_capturedPointerId);
833 m_capturedPointerId = std::nullopt;
841 if (!event.isTargetedForElement(m_window))
844 switch (event.type) {
845 case EventType::PointerDown:
846 m_capturedPointerId = event.pointerId;
847 m_window.call<
void>(
"setPointerCapture", event.pointerId);
849 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
850 != Qt::WindowDoesNotAcceptFocus
851 && window()->isTopLevel())
852 window()->requestActivate();
855 releasePointerGrab(event);
861 const bool eventAccepted = deliverPointerEvent(event);
862 if (!eventAccepted && event.type == EventType::PointerDown)
863 QGuiApplicationPrivate::instance()->closeAllPopups();
866 event.webEvent.call<
void>(
"preventDefault");
867 event.webEvent.call<
void>(
"stopPropagation");
877 const QPointF targetPointClippedToScreen(
878 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
879 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
882 const QEvent::Type eventType =
885 return eventType != QEvent::None
886 && QWindowSystemInterface::handleMouseEvent(
887 window(), QWasmIntegration::getTimestamp(),
888 window()->mapFromGlobal(targetPointClippedToScreen),
889 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
890 eventType, event.modifiers);
895 switch (event.type) {
898 pressure = event.pressure;
907 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
908 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
910 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
911 return QWindowSystemInterface::handleTabletEvent(
912 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
913 window()->mapFromGlobal(targetPointClippedToScreen),
914 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
915 event.tangentialPressure, rotation, event.modifiers);
918 QWindowSystemInterface::TouchPoint *touchPoint;
920 QPointF pointInTargetWindowCoords =
921 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
922 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
923 pointInTargetWindowCoords.y() / window()->height());
925 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
926 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
927 touchPoint = &tp.value();
929 touchPoint = &m_pointerIdToTouchPoints
930 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
938 touchPoint->state = QEventPoint::State::Pressed;
941 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
942 touchPoint->normalPosition = normalPosition;
943 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
944 .translated(-event.width / 2, -event.height / 2);
945 touchPoint->pressure = event.pressure;
947 switch (event.type) {
948 case EventType::PointerUp:
949 touchPoint->state = QEventPoint::State::Released;
951 case EventType::PointerMove:
952 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
953 : QEventPoint::State::Updated);
959 QList<QWindowSystemInterface::TouchPoint> touchPointList;
960 touchPointList.reserve(m_pointerIdToTouchPoints.size());
961 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
962 std::back_inserter(touchPointList),
963 [](
const QWindowSystemInterface::TouchPoint &val) {
return val; });
965 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
966 m_pointerIdToTouchPoints.remove(event.pointerId);
968 return event.type == EventType::PointerCancel
969 ? QWindowSystemInterface::handleTouchCancelEvent(
970 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
972 : QWindowSystemInterface::handleTouchEvent(
973 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
974 touchPointList, event.modifiers);
980 event.call<
void>(
"preventDefault");
986 const int scrollFactor = -([&event]() {
1000 return QWindowSystemInterface::handleWheelEvent(
1001 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
1002 pointInScreen, (event.delta * scrollFactor).toPoint(),
1003 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
1004 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
1008Qt::WindowFlags
QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags)
const
1010 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
1011 if (flags.testFlag(Qt::Window)) {
1012 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1013 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
1015 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
1016 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1018 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1019 flags |= Qt::FramelessWindowHint;
1024bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags)
const
1032 if (flags.testFlag(Qt::Tool) ||
1033 flags.testFlag(Qt::SplashScreen) ||
1034 flags.testFlag(Qt::ToolTip) ||
1035 flags.testFlag(Qt::Popup))
1043QWasmWindowStack<>::PositionPreference
QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
const
1045 flags = fixTopLevelWindowFlags(flags);
1047 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1048 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1049 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1050 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1051 if (shouldBeAboveTransientParentFlags(flags))
1052 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1053 return QWasmWindowStack<>::PositionPreference::Regular;
1058 return m_normalGeometry;
1063 return screen()->devicePixelRatio();
1073 return !m_flags.testFlag(Qt::FramelessWindowHint);
1078 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1079 && !windowIsPopupType(m_flags) && !parent();
1084 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1089 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1094 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1097bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags)
const
1099 if (flags.testFlag(Qt::Tool))
1102 return (flags.testFlag(Qt::Popup));
1107 QWindow *modalWindow;
1108 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1118 QPlatformWindow::requestActivateWindow();
1123 if (QWasmAccessibility::isEnabled())
1126 m_focusHelper.call<
void>(
"focus");
1131 m_focusHelper.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1132 m_inputElement.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1143 switch (event->type()) {
1144 case QEvent::WindowBlocked:
1145 m_decoratedWindow[
"classList"].call<
void>(
"add", emscripten::val(
"blocked"));
1147 case QEvent::WindowUnblocked:;
1148 m_decoratedWindow[
"classList"].call<
void>(
"remove", emscripten::val(
"blocked"));
1151 return QPlatformWindow::windowEvent(event);
1157 if (region.isEmpty()) {
1158 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(
""));
1162 std::ostringstream cssClipPath;
1163 cssClipPath <<
"path('";
1164 for (
const auto &rect : region) {
1165 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1166 cssClipPath <<
"M " << cssRect.left() <<
" " << cssRect.top() <<
" ";
1167 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.top() <<
" ";
1168 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.bottom() <<
" ";
1169 cssClipPath <<
"L " << cssRect.left() <<
" " << cssRect.bottom() <<
" z ";
1171 cssClipPath <<
"')";
1172 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(cssClipPath.str()));
1175void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1177 Q_UNUSED(newTransientParent);
1179 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1180 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1181 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1186 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1187 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1188 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1195 setWindowFlags(window()->flags());
1197 commitParent(parentNode());
1202 return "!qtwindow" +
std::to_string(m_winId);
1223 QWasmWindowStack<>::PositionPreference positionPreference)
1226 previous->containerElement().call<
void>(
"removeChild", m_decoratedWindow);
1228 current->containerElement().call<
void>(
"appendChild", m_decoratedWindow);
1229 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
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 ...
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.
std::string canvasSelector() const
QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore, WId nativeHandle)
friend class QWasmCompositor
void onNonClientAreaInteraction()
void setGeometry(const QRect &) override
This function is called by Qt whenever a window is moved or resized using the QWindow API.
bool setMouseGrabEnabled(bool grab) final
bool onNonClientEvent(const PointerEvent &event)
void setWindowCursor(QByteArray cssCursorName)
void setZOrder(int order)
void setMask(const QRegion ®ion) final
Reimplement to be able to let Qt set the mask of a window.
QWasmWindow * transientParent() const
QWasmWindowTreeNode * parentNode() final
void initialize() override
Called as part of QWindow::create(), after constructing the window.
Qt::WindowFlags windowFlags() const
void registerEventHandlers()
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 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
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()
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)