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");
462 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
464 m_canvas.set(
"width", canvasSize.width());
465 m_canvas.set(
"height", canvasSize.height());
467 bool shouldInvalidate =
true;
468 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
469 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
470 m_normalGeometry = clientAreaRect;
474 if (wasmInput && (QGuiApplication::focusWindow() == window()))
475 wasmInput->updateGeometry();
477 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
478 if (shouldInvalidate)
481 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
487 const bool nowVisible = m_decoratedWindow[
"style"][
"display"].as<std::string>() ==
"block";
488 if (visible == nowVisible)
492 m_decoratedWindow[
"style"].set(
"display", visible ?
"block" :
"none");
493 if (window() == QGuiApplication::focusWindow())
498#if QT_CONFIG(accessibility)
499 QWasmAccessibility::onShowWindow(window());
506 return window()->isVisible();
511 const auto frameRect =
512 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>(
"getBoundingClientRect"));
513 const auto canvasRect =
514 QRectF::fromDOMRect(m_window.call<emscripten::val>(
"getBoundingClientRect"));
515 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
516 frameRect.right() - canvasRect.right(),
517 frameRect.bottom() - canvasRect.bottom())
542 m_nonClientArea->propagateSizeHints();
547 m_decoratedWindow[
"style"].set(
"opacity", qBound(0.0, level, 1.0));
552 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
557 dom::syncCSSClassWith(m_decoratedWindow,
"inactive", !active);
562 flags = fixTopLevelWindowFlags(flags);
564 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
565 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
566 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
567 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
568 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
571 dom::syncCSSClassWith(m_decoratedWindow,
"frameless", !hasFrame() || !window()->isTopLevel());
572 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
573 dom::syncCSSClassWith(m_decoratedWindow,
"has-shadow", hasShadow());
574 dom::syncCSSClassWith(m_decoratedWindow,
"has-title", hasTitleBar());
575 dom::syncCSSClassWith(m_decoratedWindow,
"transparent-for-input",
576 flags.testFlag(Qt::WindowTransparentForInput));
578 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
579 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
586 newState &= Qt::WindowActive;
588 const Qt::WindowStates oldState = m_state;
590 if (newState.testFlag(Qt::WindowMinimized)) {
591 newState.setFlag(Qt::WindowMinimized,
false);
592 qWarning(
"Qt::WindowMinimized is not implemented in wasm");
593 window()->setWindowStates(newState);
597 if (newState == oldState)
601 m_previousWindowState = oldState;
608 m_nonClientArea->titleBar()->setTitle(title);
613 const auto dpi = screen()->devicePixelRatio();
614 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
615 if (pixmap.isNull()) {
616 m_nonClientArea->titleBar()->setIcon(
617 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo),
"svg+xml");
622 QBuffer buffer(&bytes);
623 pixmap.save(&buffer,
"png");
624 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(),
"png");
631 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
632 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
635 else if (isMaximized)
636 newGeom =
platformScreen()->availableGeometry().marginsRemoved(frameMargins());
640 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
641 dom::syncCSSClassWith(m_decoratedWindow,
"maximized", isMaximized);
643 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
644 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
647 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
651void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
653 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
654 m_commitedParent = parent;
659 qCDebug(qLcQpaWasmInputContext) <<
"handleKeyEvent";
661 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) {
662 handleKeyForInputContextEvent(event);
664 if (processKey(event)) {
665 event.webEvent.call<
void>(
"preventDefault");
666 event.webEvent.call<
void>(
"stopPropagation");
673 constexpr bool ProceedToNativeEvent =
false;
676#if QT_CONFIG(clipboard)
677 const auto clipboardResult =
678 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
680 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
681 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
682 return ProceedToNativeEvent;
685 const auto result = QWindowSystemInterface::handleKeyEvent(
686 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
687 event.modifiers, event.text, event.autoRepeat);
689#if QT_CONFIG(clipboard)
690 return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
691 ? ProceedToNativeEvent
707 qCDebug(qLcQpaWasmInputContext) <<
"processKey as KeyEvent";
709 if (processKeyForInputContext(keyEvent))
710 event.call<
void>(
"preventDefault");
711 event.call<
void>(
"stopImmediatePropagation");
716 qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
719 QKeySequence keySeq(event.modifiers | event.key);
721 if (keySeq == QKeySequence::Paste) {
726 const auto result = QWindowSystemInterface::handleKeyEvent(
727 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
728 event.modifiers, event.text);
730#if QT_CONFIG(clipboard)
732 if (keySeq == QKeySequence::Copy || keySeq == QKeySequence::Cut)
741 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
742 inputContext->inputCallback(event);
744 m_focusHelper.set(
"innerHTML", std::string());
749 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
750 inputContext->compositionStartCallback(event);
752 m_focusHelper.set(
"innerHTML", std::string());
757 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
758 inputContext->compositionUpdateCallback(event);
760 m_focusHelper.set(
"innerHTML", std::string());
765 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
766 inputContext->compositionEndCallback(event);
768 m_focusHelper.set(
"innerHTML", std::string());
773 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
774 inputContext->beforeInputCallback(event);
776 m_focusHelper.set(
"innerHTML", std::string());
781 if (processPointerEnterLeave(event))
782 event.webEvent.call<
void>(
"preventDefault");
790 switch (event.type) {
794 QWindowSystemInterface::handleEnterEvent(
795 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
812 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
813 m_window.call<
bool>(
"hasPointerCapture", *m_capturedPointerId)) {
814 m_window.call<
void>(
"releasePointerCapture", *m_capturedPointerId);
815 m_capturedPointerId = std::nullopt;
823 if (!event.isTargetedForElement(m_window))
826 switch (event.type) {
827 case EventType::PointerDown:
828 m_capturedPointerId = event.pointerId;
829 m_window.call<
void>(
"setPointerCapture", event.pointerId);
831 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
832 != Qt::WindowDoesNotAcceptFocus
833 && window()->isTopLevel())
834 window()->requestActivate();
837 releasePointerGrab(event);
843 const bool eventAccepted = deliverPointerEvent(event);
844 if (!eventAccepted && event.type == EventType::PointerDown)
845 QGuiApplicationPrivate::instance()->closeAllPopups();
848 event.webEvent.call<
void>(
"preventDefault");
849 event.webEvent.call<
void>(
"stopPropagation");
859 const QPointF targetPointClippedToScreen(
860 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
861 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
864 const QEvent::Type eventType =
867 return eventType != QEvent::None
868 && QWindowSystemInterface::handleMouseEvent(
869 window(), QWasmIntegration::getTimestamp(),
870 window()->mapFromGlobal(targetPointClippedToScreen),
871 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
872 eventType, event.modifiers);
877 switch (event.type) {
880 pressure = event.pressure;
889 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
890 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
892 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
893 return QWindowSystemInterface::handleTabletEvent(
894 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
895 window()->mapFromGlobal(targetPointClippedToScreen),
896 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
897 event.tangentialPressure, rotation, event.modifiers);
900 QWindowSystemInterface::TouchPoint *touchPoint;
902 QPointF pointInTargetWindowCoords =
903 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
904 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
905 pointInTargetWindowCoords.y() / window()->height());
907 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
908 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
909 touchPoint = &tp.value();
911 touchPoint = &m_pointerIdToTouchPoints
912 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
920 touchPoint->state = QEventPoint::State::Pressed;
923 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
924 touchPoint->normalPosition = normalPosition;
925 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
926 .translated(-event.width / 2, -event.height / 2);
927 touchPoint->pressure = event.pressure;
929 switch (event.type) {
930 case EventType::PointerUp:
931 touchPoint->state = QEventPoint::State::Released;
933 case EventType::PointerMove:
934 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
935 : QEventPoint::State::Updated);
941 QList<QWindowSystemInterface::TouchPoint> touchPointList;
942 touchPointList.reserve(m_pointerIdToTouchPoints.size());
943 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
944 std::back_inserter(touchPointList),
945 [](
const QWindowSystemInterface::TouchPoint &val) {
return val; });
947 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
948 m_pointerIdToTouchPoints.remove(event.pointerId);
950 return event.type == EventType::PointerCancel
951 ? QWindowSystemInterface::handleTouchCancelEvent(
952 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
954 : QWindowSystemInterface::handleTouchEvent(
955 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
956 touchPointList, event.modifiers);
962 event.call<
void>(
"preventDefault");
968 const int scrollFactor = -([&event]() {
982 return QWindowSystemInterface::handleWheelEvent(
983 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
984 pointInScreen, (event.delta * scrollFactor).toPoint(),
985 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
986 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
990Qt::WindowFlags
QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags)
const
992 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
993 if (flags.testFlag(Qt::Window)) {
994 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
995 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
997 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
998 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1000 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1001 flags |= Qt::FramelessWindowHint;
1006bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags)
const
1014 if (flags.testFlag(Qt::Tool) ||
1015 flags.testFlag(Qt::SplashScreen) ||
1016 flags.testFlag(Qt::ToolTip) ||
1017 flags.testFlag(Qt::Popup))
1025QWasmWindowStack<>::PositionPreference
QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
const
1027 flags = fixTopLevelWindowFlags(flags);
1029 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1030 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1031 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1032 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1033 if (shouldBeAboveTransientParentFlags(flags))
1034 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1035 return QWasmWindowStack<>::PositionPreference::Regular;
1040 return m_normalGeometry;
1045 return screen()->devicePixelRatio();
1055 return !m_flags.testFlag(Qt::FramelessWindowHint);
1060 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1061 && !windowIsPopupType(m_flags) && !parent();
1066 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1071 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1076 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1079bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags)
const
1081 if (flags.testFlag(Qt::Tool))
1084 return (flags.testFlag(Qt::Popup));
1089 QWindow *modalWindow;
1090 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1100 QPlatformWindow::requestActivateWindow();
1105 if (QWasmAccessibility::isEnabled())
1108 m_focusHelper.call<
void>(
"focus");
1113 m_focusHelper.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1114 m_inputElement.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1125 switch (event->type()) {
1126 case QEvent::WindowBlocked:
1127 m_decoratedWindow[
"classList"].call<
void>(
"add", emscripten::val(
"blocked"));
1129 case QEvent::WindowUnblocked:;
1130 m_decoratedWindow[
"classList"].call<
void>(
"remove", emscripten::val(
"blocked"));
1133 return QPlatformWindow::windowEvent(event);
1139 if (region.isEmpty()) {
1140 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(
""));
1144 std::ostringstream cssClipPath;
1145 cssClipPath <<
"path('";
1146 for (
const auto &rect : region) {
1147 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1148 cssClipPath <<
"M " << cssRect.left() <<
" " << cssRect.top() <<
" ";
1149 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.top() <<
" ";
1150 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.bottom() <<
" ";
1151 cssClipPath <<
"L " << cssRect.left() <<
" " << cssRect.bottom() <<
" z ";
1153 cssClipPath <<
"')";
1154 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(cssClipPath.str()));
1157void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1159 Q_UNUSED(newTransientParent);
1161 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1162 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1163 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1168 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1169 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1170 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1177 setWindowFlags(window()->flags());
1179 commitParent(parentNode());
1184 return "!qtwindow" +
std::to_string(m_winId);
1205 QWasmWindowStack<>::PositionPreference positionPreference)
1208 previous->containerElement().call<
void>(
"removeChild", m_decoratedWindow);
1210 current->containerElement().call<
void>(
"appendChild", m_decoratedWindow);
1211 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)