4#include <qpa/qwindowsysteminterface.h>
5#include <private/qguiapplication_p.h>
6#include <QtCore/qfile.h>
7#include <QtGui/private/qwindow_p.h>
8#include <QtGui/private/qhighdpiscaling_p.h>
9#include <private/qpixmapcache_p.h>
10#include <QtGui/qopenglfunctions.h>
15#if QT_CONFIG(clipboard)
16#include "qwasmclipboard.h"
26#if QT_CONFIG(draganddrop)
34#include <emscripten/val.h>
36#include <QtCore/private/qstdweb_p.h>
37#include <QKeySequence>
47 m_compositor(compositor),
48 m_backingStore(backingStore),
58 m_decoratedWindow.set(
"className",
"qt-decorated-window");
59 m_decoratedWindow[
"style"].set(
"display", std::string(
"none"));
61 m_nonClientArea = std::make_unique<NonClientArea>(
this, m_decoratedWindow);
62 m_nonClientArea->titleBar()->setTitle(window()->title());
73 m_window = *(emscripten::val *)(nativeHandle);
74 m_winId = nativeHandle;
75 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
76 m_decoratedWindow.call<
void>(
"appendChild", m_window);
80 m_window.set(
"className",
"qt-window");
81 m_decoratedWindow.call<
void>(
"appendChild", m_window);
83 m_canvas[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-canvas"));
85#if QT_CONFIG(clipboard)
86 if (QWasmClipboard::shouldInstallWindowEventHandlers()) {
87 m_cutCallback = QWasmEventHandler(m_canvas,
"cut", QWasmClipboard::cut);
88 m_copyCallback = QWasmEventHandler(m_canvas,
"copy", QWasmClipboard::copy);
89 m_pasteCallback = QWasmEventHandler(m_canvas,
"paste", QWasmClipboard::paste);
97 m_focusHelper[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-focus-helper"));
98 m_focusHelper.set(
"inputMode", std::string(
"none"));
99 m_focusHelper.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
100 m_focusHelper[
"style"].set(
"position",
"absolute");
101 m_focusHelper[
"style"].set(
"left", 0);
102 m_focusHelper[
"style"].set(
"top", 0);
103 m_focusHelper[
"style"].set(
"width",
"1px");
104 m_focusHelper[
"style"].set(
"height",
"1px");
105 m_focusHelper[
"style"].set(
"z-index", -2);
106 m_focusHelper[
"style"].set(
"opacity", 0);
107 m_window.call<
void>(
"appendChild", m_focusHelper);
111 m_inputElement[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-input-element"));
112 m_inputElement.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
113 m_inputElement.set(
"type",
"text");
114 m_inputElement[
"style"].set(
"position",
"absolute");
115 m_inputElement[
"style"].set(
"left", 0);
116 m_inputElement[
"style"].set(
"top", 0);
117 m_inputElement[
"style"].set(
"width",
"1px");
118 m_inputElement[
"style"].set(
"height",
"1px");
119 m_inputElement[
"style"].set(
"z-index", -2);
120 m_inputElement[
"style"].set(
"opacity", 0);
121 m_inputElement[
"style"].set(
"display",
"");
122 m_window.call<
void>(
"appendChild", m_inputElement);
125 m_canvas.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
126 m_canvas[
"style"].set(
"pointerEvents",
"none");
128 m_window.call<
void>(
"appendChild", m_canvas);
130 m_a11yContainer[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-a11y-container"));
131 m_window.call<
void>(
"appendChild", m_a11yContainer);
133 if (QWasmAccessibility::isEnabled())
136 const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
137 if (rendersTo2dContext)
138 m_context2d = m_canvas.call<emscripten::val>(
"getContext", emscripten::val(
"2d"));
140 m_winId = WId(&m_window);
141 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
142 emscripten::val::module_property(
"specialHTMLTargets").set(canvasSelector(), m_canvas);
144 m_flags = window()->flags();
148 m_transientWindowChangedConnection =
150 window(), &QWindow::transientParentChanged,
151 window(), [
this](QWindow *tp) { onTransientParentChanged(tp); });
153 m_modalityChangedConnection =
155 window(), &QWindow::modalityChanged,
156 window(), [
this](Qt::WindowModality) { onModalityChanged(); });
163 m_pointerDownCallback = QWasmEventHandler(m_window,
"pointerdown",
164 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); }
166 m_pointerMoveCallback = QWasmEventHandler(m_window,
"pointermove",
167 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); }
169 m_pointerUpCallback = QWasmEventHandler(m_window,
"pointerup",
170 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); }
172 m_pointerCancelCallback = QWasmEventHandler(m_window,
"pointercancel",
173 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); }
175 m_pointerEnterCallback = QWasmEventHandler(m_window,
"pointerenter",
176 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); }
178 m_pointerLeaveCallback = QWasmEventHandler(m_window,
"pointerleave",
179 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); }
182#if QT_CONFIG(draganddrop)
183 m_window.call<
void>(
"setAttribute", emscripten::val(
"draggable"), emscripten::val(
"true"));
184 m_dragStartCallback = QWasmEventHandler(m_window,
"dragstart",
185 [
this](emscripten::val event) {
186 DragEvent dragEvent(EventType::DragStart, event, window());
187 QWasmDrag::instance()->onNativeDragStarted(&dragEvent);
190 m_dragOverCallback = QWasmEventHandler(m_window,
"dragover",
191 [
this](emscripten::val event) {
192 DragEvent dragEvent(EventType::DragOver, event, window());
193 QWasmDrag::instance()->onNativeDragOver(&dragEvent);
196 m_dropCallback = QWasmEventHandler(m_window,
"drop",
197 [
this](emscripten::val event) {
198 DragEvent dragEvent(EventType::Drop, event, window());
199 QWasmDrag::instance()->onNativeDrop(&dragEvent);
202 m_dragEndCallback = QWasmEventHandler(m_window,
"dragend",
203 [
this](emscripten::val event) {
204 DragEvent dragEvent(EventType::DragEnd, event, window());
205 QWasmDrag::instance()->onNativeDragFinished(&dragEvent, platformScreen());
206 releasePointerGrab(dragEvent);
209 m_dragEnterCallback = QWasmEventHandler(m_window,
"dragenter",
210 [
this](emscripten::val event) {
211 DragEvent dragEvent(EventType::DragEnter, event, window());
212 QWasmDrag::instance()->onNativeDragEnter(&dragEvent);
215 m_dragLeaveCallback = QWasmEventHandler(m_window,
"dragleave",
216 [
this](emscripten::val event) {
217 DragEvent dragEvent(EventType::DragLeave, event, window());
218 QWasmDrag::instance()->onNativeDragLeave(&dragEvent);
223 m_wheelEventCallback = QWasmEventHandler(m_window,
"wheel",
224 [
this](emscripten::val event) {
this->handleWheelEvent(event); });
226 m_keyDownCallback = QWasmEventHandler(m_window,
"keydown",
227 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyDown, event)); });
228 m_keyUpCallback =QWasmEventHandler(m_window,
"keyup",
229 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyUp, event)); });
231 m_inputCallback = QWasmEventHandler(m_window,
"input",
232 [
this](emscripten::val event){ handleInputEvent(event); });
233 m_compositionUpdateCallback = QWasmEventHandler(m_window,
"compositionupdate",
234 [
this](emscripten::val event){ handleCompositionUpdateEvent(event); });
235 m_compositionStartCallback = QWasmEventHandler(m_window,
"compositionstart",
236 [
this](emscripten::val event){ handleCompositionStartEvent(event); });
237 m_compositionEndCallback = QWasmEventHandler(m_window,
"compositionend",
238 [
this](emscripten::val event){ handleCompositionEndEvent(event); });
239 m_beforeInputCallback = QWasmEventHandler(m_window,
"beforeinput",
240 [
this](emscripten::val event){ handleBeforeInputEvent(event); });
247#if QT_CONFIG(accessibility)
248 QWasmAccessibility::onRemoveWindow(window());
250 QObject::disconnect(m_transientWindowChangedConnection);
251 QObject::disconnect(m_modalityChangedConnection);
255 emscripten::val::module_property(
"specialHTMLTargets").delete_(canvasSelector());
256 m_window.call<
void>(
"removeChild", m_canvas);
257 m_window.call<
void>(
"removeChild", m_a11yContainer);
258 m_context2d = emscripten::val::undefined();
259 commitParent(
nullptr);
260 if (m_requestAnimationFrameId > -1)
261 emscripten_cancel_animation_frame(m_requestAnimationFrameId);
267 (QGuiApplication::focusWindow() &&
268 QGuiApplication::focusWindow() != window()))
274 std::map<uint64_t, QWasmWindow *> allWindows;
275 for (
const auto &w : platformScreen()->allWindows()) {
276 if (w->getActiveIndex() > 0)
277 allWindows.insert({w->getActiveIndex(), w});
281 if (getActiveIndex() > 0)
282 allWindows.insert({getActiveIndex(),
this});
284 if (allWindows.size() >= 2) {
285 const auto lastIt =
std::prev(allWindows.end());
286 const auto prevIt =
std::prev(lastIt);
287 const auto lastW = lastIt->second;
288 const auto prevW = prevIt->second;
291 prevW->requestActivateWindow();
297 return window()->requestedFormat();
302 if (!window ||!window->handle())
304 return static_cast<
QWasmWindow *>(window->handle());
317 return window()->flags();
322 return window()->isModal();
327 window()->setWindowState(Qt::WindowNoState);
332 window()->setWindowState(Qt::WindowMaximized);
337 window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
338 : Qt::WindowMaximized);
349 QGuiApplicationPrivate::instance()->closeAllPopups();
356 return QWindowSystemInterface::handleMouseEvent(
357 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
358 pointInScreen, event.mouseButtons, event.mouseButton,
359 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
365 auto initialGeometry = QPlatformWindow::initialGeometry(window(),
366 windowGeometry(), defaultWindowSize, defaultWindowSize);
367 m_normalGeometry = initialGeometry;
369 setWindowState(window()->windowStates());
370 setWindowFlags(window()->flags());
371 setWindowTitle(window()->title());
372 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
374 if (window()->isTopLevel())
375 setWindowIcon(window()->icon());
376 QPlatformWindow::setGeometry(m_normalGeometry);
378#if QT_CONFIG(accessibility)
381 if (window()->isTopLevel())
382 QWasmAccessibility::addAccessibilityEnableButton(window());
388 return static_cast<
QWasmScreen *>(window()->screen()->handle());
393 if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
396 auto image = m_backingStore->getUpdatedWebImage(
this);
397 if (image.isUndefined())
399 m_context2d.call<
void>(
"putImageData", image, emscripten::val(0), emscripten::val(0));
404 m_decoratedWindow[
"style"].set(
"zIndex", std::to_string(z));
409 m_window[
"style"].set(
"cursor", emscripten::val(cssCursorName.constData()));
414 const auto margins = frameMargins();
416 const QRect clientAreaRect = ([
this, &rect, &margins]() {
417 if (m_state.testFlag(Qt::WindowFullScreen))
418 return platformScreen()->geometry();
419 if (m_state.testFlag(Qt::WindowMaximized))
420 return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
422 auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
425 auto containerGeometryInViewport =
426 QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
427 "getBoundingClientRect"))
430 auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
432 QRect cappedGeometry(rectInViewport);
435 cappedGeometry.moveTop(
436 std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
437 containerGeometryInViewport.y() + margins.top()));
439 cappedGeometry.setSize(
440 cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
441 return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
444 m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
446 const auto frameRect =
448 .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
449 .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
451 m_decoratedWindow[
"style"].set(
"left", std::to_string(frameRect.left()) +
"px");
452 m_decoratedWindow[
"style"].set(
"top", std::to_string(frameRect.top()) +
"px");
453 m_canvas[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
454 m_canvas[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
455 m_a11yContainer[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
456 m_a11yContainer[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
459 m_window[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
461 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
463 m_canvas.set(
"width", canvasSize.width());
464 m_canvas.set(
"height", canvasSize.height());
466 bool shouldInvalidate =
true;
467 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
468 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
469 m_normalGeometry = clientAreaRect;
473 if (wasmInput && (QGuiApplication::focusWindow() == window()))
474 wasmInput->updateGeometry();
476 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
477 if (shouldInvalidate)
480 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
486 const bool nowVisible = m_decoratedWindow[
"style"][
"display"].as<std::string>() ==
"block";
487 if (visible == nowVisible)
491 m_decoratedWindow[
"style"].set(
"display", visible ?
"block" :
"none");
492 if (window() == QGuiApplication::focusWindow())
497#if QT_CONFIG(accessibility)
498 QWasmAccessibility::onShowWindow(window());
505 return window()->isVisible();
510 const auto frameRect =
511 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>(
"getBoundingClientRect"));
512 const auto canvasRect =
513 QRectF::fromDOMRect(m_window.call<emscripten::val>(
"getBoundingClientRect"));
514 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
515 frameRect.right() - canvasRect.right(),
516 frameRect.bottom() - canvasRect.bottom())
541 m_nonClientArea->propagateSizeHints();
546 m_decoratedWindow[
"style"].set(
"opacity", qBound(0.0, level, 1.0));
551 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
556 dom::syncCSSClassWith(m_decoratedWindow,
"inactive", !active);
561 flags = fixTopLevelWindowFlags(flags);
563 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
564 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
565 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
566 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
567 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
570 dom::syncCSSClassWith(m_decoratedWindow,
"frameless", !hasFrame() || !window()->isTopLevel());
571 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
572 dom::syncCSSClassWith(m_decoratedWindow,
"has-shadow", hasShadow());
573 dom::syncCSSClassWith(m_decoratedWindow,
"has-title", hasTitleBar());
574 dom::syncCSSClassWith(m_decoratedWindow,
"transparent-for-input",
575 flags.testFlag(Qt::WindowTransparentForInput));
577 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
578 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
585 newState &= Qt::WindowActive;
587 const Qt::WindowStates oldState = m_state;
589 if (newState.testFlag(Qt::WindowMinimized)) {
590 newState.setFlag(Qt::WindowMinimized,
false);
591 qWarning(
"Qt::WindowMinimized is not implemented in wasm");
592 window()->setWindowStates(newState);
596 if (newState == oldState)
600 m_previousWindowState = oldState;
607 m_nonClientArea->titleBar()->setTitle(title);
612 const auto dpi = screen()->devicePixelRatio();
613 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
614 if (pixmap.isNull()) {
615 m_nonClientArea->titleBar()->setIcon(
616 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo),
"svg+xml");
621 QBuffer buffer(&bytes);
622 pixmap.save(&buffer,
"png");
623 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(),
"png");
630 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
631 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
634 else if (isMaximized)
635 newGeom =
platformScreen()->availableGeometry().marginsRemoved(frameMargins());
639 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
640 dom::syncCSSClassWith(m_decoratedWindow,
"maximized", isMaximized);
642 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
643 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
646 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
650void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
652 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
653 m_commitedParent = parent;
658 qCDebug(qLcQpaWasmInputContext) <<
"handleKeyEvent";
660 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive()) {
661 handleKeyForInputContextEvent(event);
663 if (processKey(event)) {
664 event.webEvent.call<
void>(
"preventDefault");
665 event.webEvent.call<
void>(
"stopPropagation");
672 constexpr bool ProceedToNativeEvent =
false;
675#if QT_CONFIG(clipboard)
676 const auto clipboardResult =
677 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
679 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
680 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
681 return ProceedToNativeEvent;
684 const auto result = QWindowSystemInterface::handleKeyEvent(
685 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
686 event.modifiers, event.text, event.autoRepeat);
688#if QT_CONFIG(clipboard)
689 return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
690 ? ProceedToNativeEvent
706 qCDebug(qLcQpaWasmInputContext) <<
"processKey as KeyEvent";
708 if (processKeyForInputContext(keyEvent))
709 event.call<
void>(
"preventDefault");
710 event.call<
void>(
"stopImmediatePropagation");
715 qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
718 QKeySequence keySeq(event.modifiers | event.key);
720 if (keySeq == QKeySequence::Paste) {
725 const auto result = QWindowSystemInterface::handleKeyEvent(
726 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
727 event.modifiers, event.text);
729#if QT_CONFIG(clipboard)
731 if (keySeq == QKeySequence::Copy || keySeq == QKeySequence::Cut)
740 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
741 inputContext->inputCallback(event);
743 m_focusHelper.set(
"innerHTML", std::string());
748 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
749 inputContext->compositionStartCallback(event);
751 m_focusHelper.set(
"innerHTML", std::string());
756 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
757 inputContext->compositionUpdateCallback(event);
759 m_focusHelper.set(
"innerHTML", std::string());
764 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
765 inputContext->compositionEndCallback(event);
767 m_focusHelper.set(
"innerHTML", std::string());
772 if (QWasmInputContext *inputContext = QWasmIntegration::get()->wasmInputContext(); inputContext->isActive())
773 inputContext->beforeInputCallback(event);
775 m_focusHelper.set(
"innerHTML", std::string());
780 if (processPointerEnterLeave(event))
781 event.webEvent.call<
void>(
"preventDefault");
789 switch (event.type) {
793 QWindowSystemInterface::handleEnterEvent(
794 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
811 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
812 m_window.call<
bool>(
"hasPointerCapture", *m_capturedPointerId)) {
813 m_window.call<
void>(
"releasePointerCapture", *m_capturedPointerId);
814 m_capturedPointerId = std::nullopt;
822 if (!event.isTargetedForElement(m_window))
825 switch (event.type) {
826 case EventType::PointerDown:
827 m_capturedPointerId = event.pointerId;
828 m_window.call<
void>(
"setPointerCapture", event.pointerId);
830 if ((window()->flags() & Qt::WindowDoesNotAcceptFocus)
831 != Qt::WindowDoesNotAcceptFocus
832 && window()->isTopLevel())
833 window()->requestActivate();
836 releasePointerGrab(event);
842 const bool eventAccepted = deliverPointerEvent(event);
843 if (!eventAccepted && event.type == EventType::PointerDown)
844 QGuiApplicationPrivate::instance()->closeAllPopups();
847 event.webEvent.call<
void>(
"preventDefault");
848 event.webEvent.call<
void>(
"stopPropagation");
858 const QPointF targetPointClippedToScreen(
859 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
860 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
863 const QEvent::Type eventType =
866 return eventType != QEvent::None
867 && QWindowSystemInterface::handleMouseEvent(
868 window(), QWasmIntegration::getTimestamp(),
869 window()->mapFromGlobal(targetPointClippedToScreen),
870 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
871 eventType, event.modifiers);
876 switch (event.type) {
879 pressure = event.pressure;
888 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
889 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
891 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
892 return QWindowSystemInterface::handleTabletEvent(
893 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
894 window()->mapFromGlobal(targetPointClippedToScreen),
895 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
896 event.tangentialPressure, rotation, event.modifiers);
899 QWindowSystemInterface::TouchPoint *touchPoint;
901 QPointF pointInTargetWindowCoords =
902 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
903 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
904 pointInTargetWindowCoords.y() / window()->height());
906 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
907 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
908 touchPoint = &tp.value();
910 touchPoint = &m_pointerIdToTouchPoints
911 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
919 touchPoint->state = QEventPoint::State::Pressed;
922 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
923 touchPoint->normalPosition = normalPosition;
924 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
925 .translated(-event.width / 2, -event.height / 2);
926 touchPoint->pressure = event.pressure;
928 switch (event.type) {
929 case EventType::PointerUp:
930 touchPoint->state = QEventPoint::State::Released;
932 case EventType::PointerMove:
933 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
934 : QEventPoint::State::Updated);
940 QList<QWindowSystemInterface::TouchPoint> touchPointList;
941 touchPointList.reserve(m_pointerIdToTouchPoints.size());
942 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
943 std::back_inserter(touchPointList),
944 [](
const QWindowSystemInterface::TouchPoint &val) {
return val; });
946 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
947 m_pointerIdToTouchPoints.remove(event.pointerId);
949 return event.type == EventType::PointerCancel
950 ? QWindowSystemInterface::handleTouchCancelEvent(
951 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
953 : QWindowSystemInterface::handleTouchEvent(
954 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
955 touchPointList, event.modifiers);
961 event.call<
void>(
"preventDefault");
967 const int scrollFactor = -([&event]() {
981 return QWindowSystemInterface::handleWheelEvent(
982 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
983 pointInScreen, (event.delta * scrollFactor).toPoint(),
984 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
985 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
989Qt::WindowFlags
QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags)
const
991 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
992 if (flags.testFlag(Qt::Window)) {
993 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
994 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
996 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
997 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
999 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1000 flags |= Qt::FramelessWindowHint;
1005bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags)
const
1013 if (flags.testFlag(Qt::Tool) ||
1014 flags.testFlag(Qt::SplashScreen) ||
1015 flags.testFlag(Qt::ToolTip) ||
1016 flags.testFlag(Qt::Popup))
1024QWasmWindowStack<>::PositionPreference
QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
const
1026 flags = fixTopLevelWindowFlags(flags);
1028 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1029 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1030 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1031 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1032 if (shouldBeAboveTransientParentFlags(flags))
1033 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1034 return QWasmWindowStack<>::PositionPreference::Regular;
1039 return m_normalGeometry;
1044 return screen()->devicePixelRatio();
1054 return !m_flags.testFlag(Qt::FramelessWindowHint);
1059 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1060 && !windowIsPopupType(m_flags) && !parent();
1065 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1070 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1075 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1078bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags)
const
1080 if (flags.testFlag(Qt::Tool))
1083 return (flags.testFlag(Qt::Popup));
1088 QWindow *modalWindow;
1089 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1099 QPlatformWindow::requestActivateWindow();
1104 if (QWasmAccessibility::isEnabled())
1107 m_focusHelper.call<
void>(
"focus");
1112 m_focusHelper.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1113 m_inputElement.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1124 switch (event->type()) {
1125 case QEvent::WindowBlocked:
1126 m_decoratedWindow[
"classList"].call<
void>(
"add", emscripten::val(
"blocked"));
1128 case QEvent::WindowUnblocked:;
1129 m_decoratedWindow[
"classList"].call<
void>(
"remove", emscripten::val(
"blocked"));
1132 return QPlatformWindow::windowEvent(event);
1138 if (region.isEmpty()) {
1139 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(
""));
1143 std::ostringstream cssClipPath;
1144 cssClipPath <<
"path('";
1145 for (
const auto &rect : region) {
1146 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1147 cssClipPath <<
"M " << cssRect.left() <<
" " << cssRect.top() <<
" ";
1148 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.top() <<
" ";
1149 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.bottom() <<
" ";
1150 cssClipPath <<
"L " << cssRect.left() <<
" " << cssRect.bottom() <<
" z ";
1152 cssClipPath <<
"')";
1153 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(cssClipPath.str()));
1156void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1158 Q_UNUSED(newTransientParent);
1160 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1161 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1162 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1167 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1168 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1169 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1176 setWindowFlags(window()->flags());
1178 commitParent(parentNode());
1183 return "!qtwindow" +
std::to_string(m_winId);
1204 QWasmWindowStack<>::PositionPreference positionPreference)
1207 previous->containerElement().call<
void>(
"removeChild", m_decoratedWindow);
1209 current->containerElement().call<
void>(
"appendChild", m_decoratedWindow);
1210 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)