5#include <qpa/qwindowsysteminterface.h>
6#include <private/qguiapplication_p.h>
7#include <QtCore/qfile.h>
8#include <QtCore/qtimer.h>
9#include <QtCore/qpointer.h>
10#include <QtGui/private/qwindow_p.h>
11#include <QtGui/private/qhighdpiscaling_p.h>
12#include <private/qpixmapcache_p.h>
13#include <QtGui/qopenglfunctions.h>
18#if QT_CONFIG(clipboard)
19#include "qwasmclipboard.h"
30#if QT_CONFIG(draganddrop)
38#include <emscripten/val.h>
40#include <QtCore/private/qstdweb_p.h>
50 m_compositor(compositor),
51 m_backingStore(backingStore),
61 m_decoratedWindow.set(
"className",
"qt-decorated-window");
62 m_decoratedWindow[
"style"].set(
"display", std::string(
"none"));
64 m_nonClientArea = std::make_unique<NonClientArea>(
this, m_decoratedWindow);
65 m_nonClientArea->titleBar()->setTitle(window()->title());
76 m_window = *(emscripten::val *)(nativeHandle);
77 m_winId = nativeHandle;
78 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
79 m_decoratedWindow.call<
void>(
"appendChild", m_window);
83 m_window.set(
"className",
"qt-window");
84 m_decoratedWindow.call<
void>(
"appendChild", m_window);
86 m_canvas[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-canvas"));
88#if QT_CONFIG(clipboard)
89 if (QWasmClipboard::shouldInstallWindowEventHandlers()) {
90 m_cutCallback = QWasmEventHandler(m_canvas,
"cut", QWasmClipboard::cut);
91 m_copyCallback = QWasmEventHandler(m_canvas,
"copy", QWasmClipboard::copy);
92 m_pasteCallback = QWasmEventHandler(m_canvas,
"paste", QWasmClipboard::paste);
100 m_focusHelper[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-focus-helper"));
101 m_focusHelper.set(
"inputMode", std::string(
"none"));
102 m_focusHelper.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
103 m_focusHelper[
"style"].set(
"position",
"absolute");
104 m_focusHelper[
"style"].set(
"left", 0);
105 m_focusHelper[
"style"].set(
"top", 0);
106 m_focusHelper[
"style"].set(
"width",
"1px");
107 m_focusHelper[
"style"].set(
"height",
"1px");
108 m_focusHelper[
"style"].set(
"z-index", -2);
109 m_focusHelper[
"style"].set(
"opacity", 0);
110 m_window.call<
void>(
"appendChild", m_focusHelper);
114 m_inputElement[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-input-element"));
115 m_inputElement.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
116 m_inputElement.set(
"type",
"text");
117 m_inputElement[
"style"].set(
"position",
"absolute");
118 m_inputElement[
"style"].set(
"left", 0);
119 m_inputElement[
"style"].set(
"top", 0);
120 m_inputElement[
"style"].set(
"width",
"1px");
121 m_inputElement[
"style"].set(
"height",
"1px");
122 m_inputElement[
"style"].set(
"z-index", -2);
123 m_inputElement[
"style"].set(
"opacity", 0);
124 m_inputElement[
"style"].set(
"display",
"");
125 m_window.call<
void>(
"appendChild", m_inputElement);
128 m_canvas.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
129 m_canvas[
"style"].set(
"pointerEvents",
"none");
131 m_window.call<
void>(
"appendChild", m_canvas);
133 m_a11yContainer[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-a11y-container"));
134 m_window.call<
void>(
"appendChild", m_a11yContainer);
136 if (QWasmAccessibility::isEnabled())
139 const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
140 if (rendersTo2dContext)
141 m_context2d = m_canvas.call<emscripten::val>(
"getContext", emscripten::val(
"2d"));
143 m_winId = WId(&m_window);
144 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
145 emscripten::val::module_property(
"specialHTMLTargets").set(canvasSelector(), m_canvas);
147 m_flags = window()->flags();
151 m_transientWindowChangedConnection =
153 window(), &QWindow::transientParentChanged,
154 window(), [
this](QWindow *tp) { onTransientParentChanged(tp); });
156 m_modalityChangedConnection =
158 window(), &QWindow::modalityChanged,
159 window(), [
this](Qt::WindowModality) { onModalityChanged(); });
166 m_pointerDownCallback = QWasmEventHandler(m_window,
"pointerdown",
167 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); }
169 m_pointerMoveCallback = QWasmEventHandler(m_window,
"pointermove",
170 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); }
172 m_pointerUpCallback = QWasmEventHandler(m_window,
"pointerup",
173 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); }
175 m_pointerCancelCallback = QWasmEventHandler(m_window,
"pointercancel",
176 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); }
178 m_pointerEnterCallback = QWasmEventHandler(m_window,
"pointerenter",
179 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); }
181 m_pointerLeaveCallback = QWasmEventHandler(m_window,
"pointerleave",
182 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); }
185#if QT_CONFIG(draganddrop)
186 m_window.call<
void>(
"setAttribute", emscripten::val(
"draggable"), emscripten::val(
"true"));
187 m_dragStartCallback = QWasmEventHandler(m_window,
"dragstart",
188 [
this](emscripten::val event) {
189 DragEvent dragEvent(EventType::DragStart, event, window());
190 QWasmDrag::instance()->onNativeDragStarted(&dragEvent);
193 m_dragOverCallback = QWasmEventHandler(m_window,
"dragover",
194 [
this](emscripten::val event) {
195 DragEvent dragEvent(EventType::DragOver, event, window());
196 QWasmDrag::instance()->onNativeDragOver(&dragEvent);
199 m_dropCallback = QWasmEventHandler(m_window,
"drop",
200 [
this](emscripten::val event) {
201 DragEvent dragEvent(EventType::Drop, event, window());
202 QWasmDrag::instance()->onNativeDrop(&dragEvent);
205 m_dragEndCallback = QWasmEventHandler(m_window,
"dragend",
206 [
this](emscripten::val event) {
207 DragEvent dragEvent(EventType::DragEnd, event, window());
208 QWasmDrag::instance()->onNativeDragFinished(&dragEvent, platformScreen());
209 releasePointerGrab(dragEvent);
212 m_dragEnterCallback = QWasmEventHandler(m_window,
"dragenter",
213 [
this](emscripten::val event) {
214 DragEvent dragEvent(EventType::DragEnter, event, window());
215 QWasmDrag::instance()->onNativeDragEnter(&dragEvent);
218 m_dragLeaveCallback = QWasmEventHandler(m_window,
"dragleave",
219 [
this](emscripten::val event) {
220 DragEvent dragEvent(EventType::DragLeave, event, window());
221 QWasmDrag::instance()->onNativeDragLeave(&dragEvent);
226 m_wheelEventCallback = QWasmEventHandler(m_window,
"wheel",
227 [
this](emscripten::val event) {
this->handleWheelEvent(event); });
229 m_keyDownCallback = QWasmEventHandler(m_window,
"keydown",
230 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyDown, event)); });
231 m_keyUpCallback =QWasmEventHandler(m_window,
"keyup",
232 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyUp, event)); });
234 m_inputCallback = QWasmEventHandler(m_window,
"input",
235 [
this](emscripten::val event){ handleInputEvent(event); });
236 m_compositionUpdateCallback = QWasmEventHandler(m_window,
"compositionupdate",
237 [
this](emscripten::val event){ handleCompositionUpdateEvent(event); });
238 m_compositionStartCallback = QWasmEventHandler(m_window,
"compositionstart",
239 [
this](emscripten::val event){ handleCompositionStartEvent(event); });
240 m_compositionEndCallback = QWasmEventHandler(m_window,
"compositionend",
241 [
this](emscripten::val event){ handleCompositionEndEvent(event); });
242 m_beforeInputCallback = QWasmEventHandler(m_window,
"beforeinput",
243 [
this](emscripten::val event){ handleBeforeInputEvent(event); });
245 m_focusinCallback = QWasmEventHandler(m_window,
"focusin",
246 [
this](emscripten::val event) { handleFocusinEvent(event); });
247 m_focusoutCallback = QWasmEventHandler(m_window,
"focusout",
248 [
this](emscripten::val event) { handleFocusoutEvent(event); });
255#if QT_CONFIG(accessibility)
256 QWasmAccessibility::onRemoveWindow(window());
258 QObject::disconnect(m_transientWindowChangedConnection);
259 QObject::disconnect(m_modalityChangedConnection);
263 emscripten::val::module_property(
"specialHTMLTargets").delete_(canvasSelector());
264 m_window.call<
void>(
"removeChild", m_canvas);
265 m_window.call<
void>(
"removeChild", m_a11yContainer);
266 m_context2d = emscripten::val::undefined();
267 commitParent(
nullptr);
268 if (m_requestAnimationFrameId > -1)
269 emscripten_cancel_animation_frame(m_requestAnimationFrameId);
275 (QGuiApplication::focusWindow() &&
276 QGuiApplication::focusWindow() != window()))
282 std::map<uint64_t, QWasmWindow *> allWindows;
283 for (
const auto &w : platformScreen()->allWindows()) {
284 if (w->getActiveIndex() > 0 && w->isVisible())
285 allWindows.insert({w->getActiveIndex(), w});
289 if (getActiveIndex() > 0)
290 allWindows.insert({getActiveIndex(),
this});
292 if (allWindows.size() >= 2) {
293 const auto lastIt =
std::prev(allWindows.end());
294 const auto prevIt =
std::prev(lastIt);
295 const auto lastW = lastIt->second;
296 const auto prevW = prevIt->second;
299 prevW->requestActivateWindow();
305 return window()->requestedFormat();
310 if (!window ||!window->handle())
312 return static_cast<
QWasmWindow *>(window->handle());
317 return fromWindow(QGuiApplication::focusWindow());
323 return window ? window->inputElement() : emscripten::val::null();
336 return window()->flags();
341 return window()->isModal();
346 window()->setWindowState(Qt::WindowNoState);
351 window()->setWindowState(Qt::WindowMaximized);
356 window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
357 : Qt::WindowMaximized);
368 QGuiApplicationPrivate::instance()->closeAllPopups();
375 return QWindowSystemInterface::handleMouseEvent(
376 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
377 pointInScreen, event.mouseButtons, event.mouseButton,
378 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
384 auto initialGeometry = QPlatformWindow::initialGeometry(window(),
385 windowGeometry(), defaultWindowSize, defaultWindowSize);
386 m_normalGeometry = initialGeometry;
388 setWindowState(window()->windowStates());
389 setWindowFlags(window()->flags());
390 setWindowTitle(window()->title());
391 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
393 if (window()->isTopLevel())
394 setWindowIcon(window()->icon());
395 QPlatformWindow::setGeometry(m_normalGeometry);
397#if QT_CONFIG(accessibility)
400 if (window()->isTopLevel())
401 QWasmAccessibility::addAccessibilityEnableButton(window());
407 return static_cast<
QWasmScreen *>(window()->screen()->handle());
412 if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
415 auto image = m_backingStore->getUpdatedWebImage(
this);
416 if (image.isUndefined())
418 m_context2d.call<
void>(
"putImageData", image, emscripten::val(0), emscripten::val(0));
423 m_decoratedWindow[
"style"].set(
"zIndex", std::to_string(z));
428 m_window[
"style"].set(
"cursor", emscripten::val(cssCursorName.constData()));
433 const auto margins = frameMargins();
435 const QRect clientAreaRect = ([
this, &rect, &margins]() {
436 if (m_state.testFlag(Qt::WindowFullScreen))
437 return platformScreen()->geometry();
438 if (m_state.testFlag(Qt::WindowMaximized))
439 return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
441 auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
444 auto containerGeometryInViewport =
445 QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
446 "getBoundingClientRect"))
449 auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
451 QRect cappedGeometry(rectInViewport);
454 cappedGeometry.moveTop(
455 std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
456 containerGeometryInViewport.y() + margins.top()));
458 cappedGeometry.setSize(
459 cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
460 return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
463 m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
465 const auto frameRect =
467 .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
468 .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
470 m_decoratedWindow[
"style"].set(
"left", std::to_string(frameRect.left()) +
"px");
471 m_decoratedWindow[
"style"].set(
"top", std::to_string(frameRect.top()) +
"px");
472 m_canvas[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
473 m_canvas[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
474 m_a11yContainer[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
475 m_a11yContainer[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
478 m_window[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
479 m_window[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
481 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
483 m_canvas.set(
"width", canvasSize.width());
484 m_canvas.set(
"height", canvasSize.height());
486 bool shouldInvalidate =
true;
487 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
488 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
489 m_normalGeometry = clientAreaRect;
492 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
493 if (shouldInvalidate)
496 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
502 const bool nowVisible = m_decoratedWindow[
"style"][
"display"].as<std::string>() ==
"block";
503 if (visible == nowVisible)
507 m_decoratedWindow[
"style"].set(
"display", visible ?
"block" :
"none");
514 const auto flags = windowFlags();
515 const bool isTooltip = ((flags & Qt::ToolTip) == Qt::ToolTip);
516 const auto showWithoutActivatingProp = window()->property(
"_q_showWithoutActivating");
517 const bool showWithoutActivating = showWithoutActivatingProp.isValid() && showWithoutActivatingProp.toBool();
518 const bool dontFocus = isTooltip || showWithoutActivating;
521 const bool hasFocus = window() == QGuiApplication::focusWindow();
527 const bool takeFocus = window()->isTopLevel();
529 if (!dontFocus && (hasFocus || takeFocus))
532 if (window()->isTopLevel())
539#if QT_CONFIG(accessibility)
540 QWasmAccessibility::onShowWindow(window());
547 return window()->isVisible();
552 const auto frameRect =
553 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>(
"getBoundingClientRect"));
554 const auto canvasRect =
555 QRectF::fromDOMRect(m_window.call<emscripten::val>(
"getBoundingClientRect"));
556 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
557 frameRect.right() - canvasRect.right(),
558 frameRect.bottom() - canvasRect.bottom())
583 m_nonClientArea->propagateSizeHints();
588 m_decoratedWindow[
"style"].set(
"opacity", qBound(0.0, level, 1.0));
593 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
598 dom::syncCSSClassWith(m_decoratedWindow,
"inactive", !active);
603 flags = fixTopLevelWindowFlags(flags);
608 if (
std::find(childStack().begin(), childStack().end(),
this) != childStack().end()) {
609 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
610 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
611 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
612 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
613 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
617 dom::syncCSSClassWith(m_decoratedWindow,
"frameless", !hasFrame() || !window()->isTopLevel());
618 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
619 dom::syncCSSClassWith(m_decoratedWindow,
"has-shadow", hasShadow());
620 dom::syncCSSClassWith(m_decoratedWindow,
"has-title", hasTitleBar());
621 dom::syncCSSClassWith(m_decoratedWindow,
"transparent-for-input",
622 flags.testFlag(Qt::WindowTransparentForInput));
624 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
625 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
632 newState &= Qt::WindowActive;
634 const Qt::WindowStates oldState = m_state;
636 if (newState.testFlag(Qt::WindowMinimized)) {
637 newState.setFlag(Qt::WindowMinimized,
false);
638 qWarning(
"Qt::WindowMinimized is not implemented in wasm");
639 window()->setWindowStates(newState);
643 if (newState == oldState)
647 m_previousWindowState = oldState;
654 m_nonClientArea->titleBar()->setTitle(title);
659 const auto dpi = screen()->devicePixelRatio();
660 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
661 if (pixmap.isNull()) {
662 m_nonClientArea->titleBar()->setIcon(
663 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo),
"svg+xml");
668 QBuffer buffer(&bytes);
669 pixmap.save(&buffer,
"png");
670 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(),
"png");
677 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
678 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
689 else if (isMaximized)
690 newGeom =
platformScreen()->availableGeometry().marginsRemoved(frameMargins());
694 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
695 dom::syncCSSClassWith(m_decoratedWindow,
"maximized", isMaximized);
697 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
698 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
701 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
705void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
707 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
708 m_commitedParent = parent;
713 qCDebug(qLcQpaWasmInputContext) <<
"handleKeyEvent";
715 if (QWasmInputContext *inputContext = activeWasmInputContext()) {
720 if (processKey(event)) {
724 inputContext->m_ignoreNextInput =
true;
726 event.webEvent.call<
void>(
"stopImmediatePropagation");
728 if (processKey(event)) {
729 event.webEvent.call<
void>(
"preventDefault");
730 event.webEvent.call<
void>(
"stopPropagation");
737 constexpr bool ProceedToNativeEvent =
false;
743#if QT_CONFIG(clipboard)
744 const auto clipboardResult =
745 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
747 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
748 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
749 return ProceedToNativeEvent;
752 const auto result = QWindowSystemInterface::handleKeyEvent(
753 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
754 event.modifiers, event.text, event.autoRepeat);
756#if QT_CONFIG(clipboard)
757 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded)
758 return ProceedToNativeEvent;
766 if (QWasmInputContext *inputContext = activeWasmInputContext())
767 inputContext->inputCallback(event);
769 m_focusHelper.set(
"innerHTML", std::string());
774 if (QWasmInputContext *inputContext = activeWasmInputContext())
775 inputContext->compositionStartCallback(event);
777 m_focusHelper.set(
"innerHTML", std::string());
782 if (QWasmInputContext *inputContext = activeWasmInputContext())
783 inputContext->compositionUpdateCallback(event);
785 m_focusHelper.set(
"innerHTML", std::string());
790 if (QWasmInputContext *inputContext = activeWasmInputContext())
791 inputContext->compositionEndCallback(event);
793 m_focusHelper.set(
"innerHTML", std::string());
798 if (QWasmInputContext *inputContext = activeWasmInputContext())
799 inputContext->beforeInputCallback(event);
801 m_focusHelper.set(
"innerHTML", std::string());
807 emscripten::val relatedTarget = event[
"relatedTarget"];
808 bool enteringWindow = relatedTarget.isNull() || relatedTarget.isUndefined()
809 || !m_window.call<
bool>(
"contains", relatedTarget);
811 if (enteringWindow) {
813 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
820 emscripten::val relatedTarget = event[
"relatedTarget"];
821 bool leavingWindow = relatedTarget.isNull() || relatedTarget.isUndefined()
822 || !m_window.call<
bool>(
"contains", relatedTarget);
825 QWindowSystemInterface::handleFocusWindowChanged(
nullptr, Qt::ActiveWindowFocusReason);
830 if (processPointerEnterLeave(event))
831 event.webEvent.call<
void>(
"preventDefault");
839 switch (event.type) {
843 QWindowSystemInterface::handleEnterEvent(
844 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
861 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
862 m_window.call<
bool>(
"hasPointerCapture", *m_capturedPointerId)) {
863 m_window.call<
void>(
"releasePointerCapture", *m_capturedPointerId);
864 m_capturedPointerId = std::nullopt;
875 switch (event.type) {
876 case EventType::PointerDown:
877 m_capturedPointerId = event.pointerId;
878 m_window.call<
void>(
"setPointerCapture", event.pointerId);
881 if (!window()->flags().testFlag(Qt::WindowDoesNotAcceptFocus)
882 && QGuiApplication::focusWindow() != window()) {
883 QWindow *win = window();
884 while (!win->isTopLevel())
885 win = win->parent(QWindow::ExcludeTransients);
886 win->requestActivate();
891 event.webEvent.call<
void>(
"preventDefault");
895 releasePointerGrab(event);
901 const bool eventAccepted = deliverPointerEvent(event);
902 if (!eventAccepted && event.type == EventType::PointerDown)
903 QGuiApplicationPrivate::instance()->closeAllPopups();
906 event.webEvent.call<
void>(
"preventDefault");
907 event.webEvent.call<
void>(
"stopPropagation");
917 const QPointF targetPointClippedToScreen(
918 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
919 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
922 const QEvent::Type eventType =
925 return eventType != QEvent::None
926 && QWindowSystemInterface::handleMouseEvent(
927 window(), QWasmIntegration::getTimestamp(),
928 window()->mapFromGlobal(targetPointClippedToScreen),
929 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
930 eventType, event.modifiers);
935 switch (event.type) {
938 pressure = event.pressure;
947 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
948 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
950 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
951 return QWindowSystemInterface::handleTabletEvent(
952 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
953 window()->mapFromGlobal(targetPointClippedToScreen),
954 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
955 event.tangentialPressure, rotation, event.modifiers);
958 QWindowSystemInterface::TouchPoint *touchPoint;
960 QPointF pointInTargetWindowCoords =
961 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
962 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
963 pointInTargetWindowCoords.y() / window()->height());
965 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
966 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
967 touchPoint = &tp.value();
969 touchPoint = &m_pointerIdToTouchPoints
970 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
978 touchPoint->state = QEventPoint::State::Pressed;
981 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
982 touchPoint->normalPosition = normalPosition;
983 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
984 .translated(-event.width / 2, -event.height / 2);
985 touchPoint->pressure = event.pressure;
987 switch (event.type) {
988 case EventType::PointerUp:
989 touchPoint->state = QEventPoint::State::Released;
991 case EventType::PointerMove:
992 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
993 : QEventPoint::State::Updated);
999 QList<QWindowSystemInterface::TouchPoint> touchPointList;
1000 touchPointList.reserve(m_pointerIdToTouchPoints.size());
1001 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
1002 std::back_inserter(touchPointList),
1003 [](
const QWindowSystemInterface::TouchPoint &val) {
return val; });
1005 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
1006 m_pointerIdToTouchPoints.remove(event.pointerId);
1008 return event.type == EventType::PointerCancel
1009 ? QWindowSystemInterface::handleTouchCancelEvent(
1010 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
1012 : QWindowSystemInterface::handleTouchEvent(
1013 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
1014 touchPointList, event.modifiers);
1020 event.call<
void>(
"preventDefault");
1026 const int scrollFactor = -([&event]() {
1040 return QWindowSystemInterface::handleWheelEvent(
1041 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
1042 pointInScreen, (event.delta * scrollFactor).toPoint(),
1043 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
1044 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
1048Qt::WindowFlags
QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags)
const
1050 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
1051 if (flags.testFlag(Qt::Window)) {
1052 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1053 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
1055 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
1056 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1058 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1059 flags |= Qt::FramelessWindowHint;
1064bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags)
const
1072 if (flags.testFlag(Qt::Tool) ||
1073 flags.testFlag(Qt::SplashScreen) ||
1074 flags.testFlag(Qt::ToolTip) ||
1075 flags.testFlag(Qt::Popup))
1083QWasmWindowStack<>::PositionPreference
QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
const
1085 flags = fixTopLevelWindowFlags(flags);
1087 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1088 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1089 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1090 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1091 if (shouldBeAboveTransientParentFlags(flags))
1092 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1093 return QWasmWindowStack<>::PositionPreference::Regular;
1097QWasmInputContext *
QWasmWindow::activeWasmInputContext()
const
1102 if (QWasmAccessibility::isEnabled())
1105 return inputContext && inputContext->isActive() ? inputContext :
nullptr;
1110 return m_normalGeometry;
1115 return screen()->devicePixelRatio();
1125 return !m_flags.testFlag(Qt::FramelessWindowHint);
1130 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1131 && !windowIsPopupType(m_flags) && !parent();
1136 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1141 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1146 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1149bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags)
const
1151 if (flags.testFlag(Qt::Tool))
1154 return (flags.testFlag(Qt::Popup));
1159 QWindow *modalWindow;
1160 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1176 if (QWasmAccessibility::isEnabled())
1179 emscripten::val &element = target == InputFocus ? m_inputElement : m_focusHelper;
1180 element.call<
void>(
"focus");
1185 m_focusHelper.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1186 m_inputElement.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1197 switch (event->type()) {
1198 case QEvent::WindowBlocked:
1199 m_decoratedWindow[
"classList"].call<
void>(
"add", emscripten::val(
"blocked"));
1201 case QEvent::WindowUnblocked:;
1202 m_decoratedWindow[
"classList"].call<
void>(
"remove", emscripten::val(
"blocked"));
1205 return QPlatformWindow::windowEvent(event);
1211 if (region.isEmpty()) {
1212 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(
""));
1216 std::ostringstream cssClipPath;
1217 cssClipPath <<
"path('";
1218 for (
const auto &rect : region) {
1219 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1220 cssClipPath <<
"M " << cssRect.left() <<
" " << cssRect.top() <<
" ";
1221 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.top() <<
" ";
1222 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.bottom() <<
" ";
1223 cssClipPath <<
"L " << cssRect.left() <<
" " << cssRect.bottom() <<
" z ";
1225 cssClipPath <<
"')";
1226 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(cssClipPath.str()));
1229void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1231 Q_UNUSED(newTransientParent);
1233 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1234 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1235 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1240 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1241 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1242 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1249 setWindowFlags(window()->flags());
1251 commitParent(parentNode());
1256 return "!qtwindow" +
std::to_string(m_winId);
1277 QWasmWindowStack<>::PositionPreference positionPreference)
1280 previous->containerElement().call<
void>(
"removeChild", m_decoratedWindow);
1282 current->containerElement().call<
void>(
"appendChild", m_decoratedWindow);
1283 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
QRect window() const
Returns the window rectangle.
QWasmCompositor(QWasmScreen *screen)
static QWasmIntegration * get()
QWasmInputContext * wasmInputContext() const
static void destroyWebGLContext(QPlatformSurface *surface)
emscripten::val element() const
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
void setVisible(bool visible) override
Reimplemented in subclasses to show the surface if visible is true, and hide it if visible is false.
qreal devicePixelRatio() const override
Reimplement this function in subclass to return the device pixel ratio for the window.
QRect normalGeometry() const override
Returns the geometry of a window in 'normal' state (neither maximized, fullscreen nor minimized) for ...
void focus(FocusTarget target=WindowFocus)
QSurfaceFormat format() const override
Returns the actual surface format of the window.
void setParent(const QPlatformWindow *window) final
This function is called to enable native child window in QPA.
static QWasmWindow * fromWindow(const QWindow *window)
void raise() override
Reimplement to be able to let Qt raise windows to the top of the desktop.
void setWindowTitle(const QString &title) override
Reimplement to set the window title to title.
void requestActivateWindow() override
Reimplement to let Qt be able to request activation/focus for a window.
WId winId() const override
Reimplement in subclasses to return a handle to the native window.
static emscripten::val focusedWindowInputElement()
std::string canvasSelector() const
static QWasmWindow * focusWindow()
QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore, WId nativeHandle)
friend class QWasmCompositor
void onNonClientAreaInteraction()
void setGeometry(const QRect &) override
This function is called by Qt whenever a window is moved or resized using the QWindow API.
bool setMouseGrabEnabled(bool grab) final
bool onNonClientEvent(const PointerEvent &event)
void setWindowCursor(QByteArray cssCursorName)
void setZOrder(int order)
void setMask(const QRegion ®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)
bool isTargetedForElement(emscripten::val element) const