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),
63 m_decoratedWindow.set(
"className",
"qt-decorated-window");
64 m_decoratedWindow[
"style"].set(
"display", std::string(
"none"));
66 m_nonClientArea = std::make_unique<NonClientArea>(
this, m_decoratedWindow);
67 m_nonClientArea->titleBar()->setTitle(window()->title());
78 m_window = *(emscripten::val *)(nativeHandle);
79 m_winId = nativeHandle;
80 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
81 m_decoratedWindow.call<
void>(
"appendChild", m_window);
85 m_window.set(
"className",
"qt-window");
86 m_decoratedWindow.call<
void>(
"appendChild", m_window);
88 m_canvas[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-canvas"));
90#if QT_CONFIG(clipboard)
92 m_cutCallback = QWasmEventHandler(m_window,
"cut", QWasmClipboard::cut);
93 m_copyCallback = QWasmEventHandler(m_window,
"copy", QWasmClipboard::copy);
94 m_pasteCallback = QWasmEventHandler(m_window,
"paste", QWasmClipboard::paste);
101 m_focusHelper[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-focus-helper"));
102 m_focusHelper.set(
"inputMode", std::string(
"none"));
103 m_focusHelper.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
104 m_focusHelper[
"style"].set(
"position",
"absolute");
105 m_focusHelper[
"style"].set(
"left", 0);
106 m_focusHelper[
"style"].set(
"top", 0);
107 m_focusHelper[
"style"].set(
"width",
"1px");
108 m_focusHelper[
"style"].set(
"height",
"1px");
109 m_focusHelper[
"style"].set(
"z-index", -2);
110 m_focusHelper[
"style"].set(
"opacity", 0);
111 m_window.call<
void>(
"appendChild", m_focusHelper);
115 m_inputElement[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-input-element"));
116 m_inputElement.call<
void>(
"setAttribute", std::string(
"contenteditable"), std::string(
"true"));
117 m_inputElement.set(
"type",
"text");
118 m_inputElement[
"style"].set(
"position",
"absolute");
119 m_inputElement[
"style"].set(
"left", 0);
120 m_inputElement[
"style"].set(
"top", 0);
121 m_inputElement[
"style"].set(
"width",
"1px");
122 m_inputElement[
"style"].set(
"height",
"1px");
123 m_inputElement[
"style"].set(
"z-index", -2);
124 m_inputElement[
"style"].set(
"opacity", 0);
125 m_inputElement[
"style"].set(
"display",
"");
126 m_window.call<
void>(
"appendChild", m_inputElement);
129 m_canvas.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
130 m_canvas[
"style"].set(
"pointerEvents",
"none");
132 m_window.call<
void>(
"appendChild", m_canvas);
134 m_a11yContainer[
"classList"].call<
void>(
"add", emscripten::val(
"qt-window-a11y-container"));
135 m_a11yElementContainer[
"classList"].call<
void>(
136 "add", emscripten::val(
"qt-window-a11y-elements-container"));
137 m_a11yDescribedByContainer[
"classList"].call<
void>(
138 "add", emscripten::val(
"qt-window-a11y-describedby-container"));
139 m_a11yContainer.call<
void>(
"appendChild", m_a11yElementContainer);
140 m_a11yContainer.call<
void>(
"appendChild", m_a11yDescribedByContainer);
141 m_window.call<
void>(
"appendChild", m_a11yContainer);
143 if (QWasmAccessibility::isEnabled())
146 const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
147 if (rendersTo2dContext)
148 m_context2d = m_canvas.call<emscripten::val>(
"getContext", emscripten::val(
"2d"));
150 m_winId = WId(&m_window);
151 m_decoratedWindow.set(
"id",
"qt-window-" + std::to_string(m_winId));
152 emscripten::val::module_property(
"specialHTMLTargets").set(canvasSelector(), m_canvas);
154 m_flags = window()->flags();
158 m_transientWindowChangedConnection =
160 window(), &QWindow::transientParentChanged,
161 window(), [
this](QWindow *tp) { onTransientParentChanged(tp); });
163 m_modalityChangedConnection =
165 window(), &QWindow::modalityChanged,
166 window(), [
this](Qt::WindowModality) { onModalityChanged(); });
173 m_pointerDownCallback = QWasmEventHandler(m_window,
"pointerdown",
174 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); }
176 m_pointerMoveCallback = QWasmEventHandler(m_window,
"pointermove",
177 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); }
179 m_pointerUpCallback = QWasmEventHandler(m_window,
"pointerup",
180 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); }
182 m_pointerCancelCallback = QWasmEventHandler(m_window,
"pointercancel",
183 [
this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); }
185 m_pointerEnterCallback = QWasmEventHandler(m_window,
"pointerenter",
186 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); }
188 m_pointerLeaveCallback = QWasmEventHandler(m_window,
"pointerleave",
189 [
this](emscripten::val event) {
this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); }
192#if QT_CONFIG(draganddrop)
193 m_window.call<
void>(
"setAttribute", emscripten::val(
"draggable"), emscripten::val(
"true"));
194 m_dragStartCallback = QWasmEventHandler(m_window,
"dragstart",
195 [
this](emscripten::val event) {
196 DragEvent dragEvent(EventType::DragStart, event, window());
197 QWasmDrag::instance()->onNativeDragStarted(&dragEvent);
200 m_dragOverCallback = QWasmEventHandler(m_window,
"dragover",
201 [
this](emscripten::val event) {
202 DragEvent dragEvent(EventType::DragOver, event, window());
203 QWasmDrag::instance()->onNativeDragOver(&dragEvent);
206 m_dropCallback = QWasmEventHandler(m_window,
"drop",
207 [
this](emscripten::val event) {
208 DragEvent dragEvent(EventType::Drop, event, window());
209 QWasmDrag::instance()->onNativeDrop(&dragEvent);
212 m_dragEndCallback = QWasmEventHandler(m_window,
"dragend",
213 [
this](emscripten::val event) {
214 DragEvent dragEvent(EventType::DragEnd, event, window());
215 QWasmDrag::instance()->onNativeDragFinished(&dragEvent, platformScreen());
216 releasePointerGrab(dragEvent);
219 m_dragEnterCallback = QWasmEventHandler(m_window,
"dragenter",
220 [
this](emscripten::val event) {
221 DragEvent dragEvent(EventType::DragEnter, event, window());
222 QWasmDrag::instance()->onNativeDragEnter(&dragEvent);
225 m_dragLeaveCallback = QWasmEventHandler(m_window,
"dragleave",
226 [
this](emscripten::val event) {
227 DragEvent dragEvent(EventType::DragLeave, event, window());
228 QWasmDrag::instance()->onNativeDragLeave(&dragEvent);
233 m_wheelEventCallback = QWasmEventHandler(m_window,
"wheel",
234 [
this](emscripten::val event) {
this->handleWheelEvent(event); });
236 m_keyDownCallback = QWasmEventHandler(m_window,
"keydown",
237 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyDown, event)); });
238 m_keyUpCallback =QWasmEventHandler(m_window,
"keyup",
239 [
this](emscripten::val event) {
this->handleKeyEvent(KeyEvent(EventType::KeyUp, event)); });
241 m_inputCallback = QWasmEventHandler(m_window,
"input",
242 [
this](emscripten::val event){ handleInputEvent(event); });
243 m_compositionUpdateCallback = QWasmEventHandler(m_window,
"compositionupdate",
244 [
this](emscripten::val event){ handleCompositionUpdateEvent(event); });
245 m_compositionStartCallback = QWasmEventHandler(m_window,
"compositionstart",
246 [
this](emscripten::val event){ handleCompositionStartEvent(event); });
247 m_compositionEndCallback = QWasmEventHandler(m_window,
"compositionend",
248 [
this](emscripten::val event){ handleCompositionEndEvent(event); });
249 m_beforeInputCallback = QWasmEventHandler(m_window,
"beforeinput",
250 [
this](emscripten::val event){ handleBeforeInputEvent(event); });
252 m_focusinCallback = QWasmEventHandler(m_window,
"focusin",
253 [
this](emscripten::val event) { handleFocusinEvent(event); });
254 m_focusoutCallback = QWasmEventHandler(m_window,
"focusout",
255 [
this](emscripten::val event) { handleFocusoutEvent(event); });
262#if QT_CONFIG(accessibility)
263 QWasmAccessibility::onRemoveWindow(window());
265 QObject::disconnect(m_transientWindowChangedConnection);
266 QObject::disconnect(m_modalityChangedConnection);
270 emscripten::val::module_property(
"specialHTMLTargets").delete_(canvasSelector());
271 m_window.call<
void>(
"removeChild", m_canvas);
272 m_window.call<
void>(
"removeChild", m_a11yContainer);
273 m_context2d = emscripten::val::undefined();
274 commitParent(
nullptr);
275 if (m_requestAnimationFrameId > -1)
276 emscripten_cancel_animation_frame(m_requestAnimationFrameId);
282 (QGuiApplication::focusWindow() &&
283 QGuiApplication::focusWindow() != window()))
289 std::map<uint64_t, QWasmWindow *> allWindows;
290 for (
const auto &w : platformScreen()->allWindows()) {
291 if (w->getActiveIndex() > 0 && w->isVisible())
292 allWindows.insert({w->getActiveIndex(), w});
296 if (getActiveIndex() > 0)
297 allWindows.insert({getActiveIndex(),
this});
299 if (allWindows.size() >= 2) {
300 const auto lastIt =
std::prev(allWindows.end());
301 const auto prevIt =
std::prev(lastIt);
302 const auto lastW = lastIt->second;
303 const auto prevW = prevIt->second;
306 prevW->requestActivateWindow();
312 return window()->requestedFormat();
317 if (!window ||!window->handle())
319 return static_cast<
QWasmWindow *>(window->handle());
324 return fromWindow(QGuiApplication::focusWindow());
330 return window ? window->inputElement() : emscripten::val::null();
343 return window()->flags();
348 return window()->isModal();
353 window()->setWindowState(Qt::WindowNoState);
358 window()->setWindowState(Qt::WindowMaximized);
363 window()->setWindowState(m_state.testFlag(Qt::WindowMaximized) ? Qt::WindowNoState
364 : Qt::WindowMaximized);
375 QGuiApplicationPrivate::instance()->closeAllPopups();
382 return QWindowSystemInterface::handleMouseEvent(
383 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
384 pointInScreen, event.mouseButtons, event.mouseButton,
385 MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::NonClient),
391 auto initialGeometry = QPlatformWindow::initialGeometry(window(),
392 windowGeometry(), defaultWindowSize, defaultWindowSize);
393 m_normalGeometry = initialGeometry;
395 setWindowState(window()->windowStates());
396 setWindowFlags(window()->flags());
397 setWindowTitle(window()->title());
398 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
400 if (window()->isTopLevel())
401 setWindowIcon(window()->icon());
402 QPlatformWindow::setGeometry(m_normalGeometry);
404#if QT_CONFIG(accessibility)
407 if (window()->isTopLevel())
408 QWasmAccessibility::addAccessibilityEnableButton(window());
414 return static_cast<
QWasmScreen *>(window()->screen()->handle());
419 if (!m_backingStore || !isVisible() || m_context2d.isUndefined())
422 auto image = m_backingStore->getUpdatedWebImage(
this);
423 if (image.isUndefined())
425 m_context2d.call<
void>(
"putImageData", image, emscripten::val(0), emscripten::val(0));
430 m_decoratedWindow[
"style"].set(
"zIndex", std::to_string(z));
435 m_window[
"style"].set(
"cursor", emscripten::val(cssCursorName.constData()));
440 const auto margins = frameMargins();
442 const QRect clientAreaRect = ([
this, &rect, &margins]() {
443 if (m_state.testFlag(Qt::WindowFullScreen))
444 return platformScreen()->geometry();
445 if (m_state.testFlag(Qt::WindowMaximized))
446 return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
448 auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
451 auto containerGeometryInViewport =
452 QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
453 "getBoundingClientRect"))
456 auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
458 QRect cappedGeometry(rectInViewport);
461 cappedGeometry.moveTop(
462 std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
463 containerGeometryInViewport.y() + margins.top()));
465 cappedGeometry.setSize(
466 cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
467 return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
470 m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
472 const auto frameRect =
474 .adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
475 .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
477 m_decoratedWindow[
"style"].set(
"left", std::to_string(frameRect.left()) +
"px");
478 m_decoratedWindow[
"style"].set(
"top", std::to_string(frameRect.top()) +
"px");
479 m_canvas[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
480 m_canvas[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
481 m_a11yContainer[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
482 m_a11yContainer[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
485 m_window[
"style"].set(
"width", std::to_string(clientAreaRect.width()) +
"px");
486 m_window[
"style"].set(
"height", std::to_string(clientAreaRect.height()) +
"px");
488 QSizeF canvasSize = clientAreaRect.size() * devicePixelRatio();
490 m_canvas.set(
"width", canvasSize.width());
491 m_canvas.set(
"height", canvasSize.height());
493 bool shouldInvalidate =
true;
494 if (!m_state.testFlag(Qt::WindowFullScreen) && !m_state.testFlag(Qt::WindowMaximized)) {
495 shouldInvalidate = m_normalGeometry.size() != clientAreaRect.size();
496 m_normalGeometry = clientAreaRect;
499 QWindowSystemInterface::handleGeometryChange(window(), clientAreaRect);
500 if (shouldInvalidate)
503 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
509 const bool nowVisible = m_decoratedWindow[
"style"][
"display"].as<std::string>() ==
"block";
510 if (visible == nowVisible)
514 m_decoratedWindow[
"style"].set(
"display", visible ?
"block" :
"none");
521 const auto flags = windowFlags();
522 const bool isTooltip = ((flags & Qt::ToolTip) == Qt::ToolTip);
523 const auto showWithoutActivatingProp = window()->property(
"_q_showWithoutActivating");
524 const bool showWithoutActivating = showWithoutActivatingProp.isValid() && showWithoutActivatingProp.toBool();
525 const bool dontFocus = isTooltip || showWithoutActivating;
528 const bool hasFocus = window() == QGuiApplication::focusWindow();
534 const bool takeFocus = window()->isTopLevel();
536 if (!dontFocus && (hasFocus || takeFocus))
539 if (window()->isTopLevel())
546#if QT_CONFIG(accessibility)
547 QWasmAccessibility::onShowWindow(window());
554 return window()->isVisible();
559 const auto frameRect =
560 QRectF::fromDOMRect(m_decoratedWindow.call<emscripten::val>(
"getBoundingClientRect"));
561 const auto canvasRect =
562 QRectF::fromDOMRect(m_window.call<emscripten::val>(
"getBoundingClientRect"));
563 return QMarginsF(canvasRect.left() - frameRect.left(), canvasRect.top() - frameRect.top(),
564 frameRect.right() - canvasRect.right(),
565 frameRect.bottom() - canvasRect.bottom())
590 m_nonClientArea->propagateSizeHints();
595 m_decoratedWindow[
"style"].set(
"opacity", qBound(0.0, level, 1.0));
600 m_compositor->requestUpdateWindow(
this, QRect(QPoint(0, 0), geometry().size()));
605 dom::syncCSSClassWith(m_decoratedWindow,
"inactive", !active);
610 flags = fixTopLevelWindowFlags(flags);
615 if (
std::find(childStack().begin(), childStack().end(),
this) != childStack().end()) {
616 if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
617 || (flags.testFlag(Qt::WindowStaysOnBottomHint)
618 != m_flags.testFlag(Qt::WindowStaysOnBottomHint))
619 || shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
620 onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
624 dom::syncCSSClassWith(m_decoratedWindow,
"frameless", !hasFrame() || !window()->isTopLevel());
625 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
626 dom::syncCSSClassWith(m_decoratedWindow,
"has-shadow", hasShadow());
627 dom::syncCSSClassWith(m_decoratedWindow,
"has-title", hasTitleBar());
628 dom::syncCSSClassWith(m_decoratedWindow,
"transparent-for-input",
629 flags.testFlag(Qt::WindowTransparentForInput));
631 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
632 m_nonClientArea->titleBar()->setCloseVisible(m_flags.testFlag(Qt::WindowCloseButtonHint));
639 newState &= Qt::WindowActive;
641 const Qt::WindowStates oldState = m_state;
643 if (newState.testFlag(Qt::WindowMinimized)) {
644 newState.setFlag(Qt::WindowMinimized,
false);
645 qWarning(
"Qt::WindowMinimized is not implemented in wasm");
646 window()->setWindowStates(newState);
650 if (newState == oldState)
654 m_previousWindowState = oldState;
661 m_nonClientArea->titleBar()->setTitle(title);
666 const auto dpi = screen()->devicePixelRatio();
667 auto pixmap = icon.pixmap(10 * dpi, 10 * dpi);
668 if (pixmap.isNull()) {
669 m_nonClientArea->titleBar()->setIcon(
670 Base64IconStore::get()->getIcon(Base64IconStore::IconType::QtLogo),
"svg+xml");
675 QBuffer buffer(&bytes);
676 pixmap.save(&buffer,
"png");
677 m_nonClientArea->titleBar()->setIcon(bytes.toBase64().toStdString(),
"png");
684 const bool isFullscreen = m_state.testFlag(Qt::WindowFullScreen);
685 const bool isMaximized = m_state.testFlag(Qt::WindowMaximized);
694 else if (isMaximized)
695 newGeom =
platformScreen()->availableGeometry().marginsRemoved(frameMargins());
699 dom::syncCSSClassWith(m_decoratedWindow,
"has-border", hasBorder());
700 dom::syncCSSClassWith(m_decoratedWindow,
"maximized", isMaximized);
702 m_nonClientArea->titleBar()->setRestoreVisible(isMaximized);
703 m_nonClientArea->titleBar()->setMaximizeVisible(hasMaximizeButton());
706 QWindowSystemInterface::handleWindowStateChanged(window(), m_state, m_previousWindowState);
710void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
712 onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
713 m_commitedParent = parent;
718 qCDebug(qLcQpaWasmInputContext) <<
"handleKeyEvent";
720 if (QWasmInputContext *inputContext = activeWasmInputContext()) {
725 if (processKey(event)) {
729 inputContext->m_ignoreNextInput =
true;
731 event.webEvent.call<
void>(
"stopImmediatePropagation");
733 if (processKey(event)) {
734 event.webEvent.call<
void>(
"preventDefault");
735 event.webEvent.call<
void>(
"stopPropagation");
742 constexpr bool ProceedToNativeEvent =
false;
748#if QT_CONFIG(clipboard)
749 const auto clipboardResult =
750 QWasmIntegration::get()->getWasmClipboard()->processKeyboard(event);
752 using ProcessKeyboardResult = QWasmClipboard::ProcessKeyboardResult;
753 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventNeeded)
754 return ProceedToNativeEvent;
757 const auto result = QWindowSystemInterface::handleKeyEvent(
758 0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
759 event.modifiers, event.text, event.autoRepeat);
761#if QT_CONFIG(clipboard)
762 if (clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded)
763 return ProceedToNativeEvent;
771 if (QWasmInputContext *inputContext = activeWasmInputContext())
772 inputContext->inputCallback(event);
774 m_focusHelper.set(
"innerHTML", std::string());
779 if (QWasmInputContext *inputContext = activeWasmInputContext())
780 inputContext->compositionStartCallback(event);
782 m_focusHelper.set(
"innerHTML", std::string());
787 if (QWasmInputContext *inputContext = activeWasmInputContext())
788 inputContext->compositionUpdateCallback(event);
790 m_focusHelper.set(
"innerHTML", std::string());
795 if (QWasmInputContext *inputContext = activeWasmInputContext())
796 inputContext->compositionEndCallback(event);
798 m_focusHelper.set(
"innerHTML", std::string());
803 if (QWasmInputContext *inputContext = activeWasmInputContext())
804 inputContext->beforeInputCallback(event);
806 m_focusHelper.set(
"innerHTML", std::string());
812 emscripten::val relatedTarget = event[
"relatedTarget"];
813 bool enteringWindow = relatedTarget.isNull() || relatedTarget.isUndefined()
814 || !m_window.call<
bool>(
"contains", relatedTarget);
816 if (enteringWindow) {
818 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
825 emscripten::val relatedTarget = event[
"relatedTarget"];
826 bool leavingWindow = relatedTarget.isNull() || relatedTarget.isUndefined()
827 || !m_window.call<
bool>(
"contains", relatedTarget);
830 QWindowSystemInterface::handleFocusWindowChanged(
nullptr, Qt::ActiveWindowFocusReason);
835 if (processPointerEnterLeave(event))
836 event.webEvent.call<
void>(
"preventDefault");
844 switch (event.type) {
848 QWindowSystemInterface::handleEnterEvent(
849 window(), mapFromGlobal(pointInScreen.toPoint()), pointInScreen);
866 if (m_capturedPointerId && event.isTargetedForElement(m_window) &&
867 m_window.call<
bool>(
"hasPointerCapture", *m_capturedPointerId)) {
868 m_window.call<
void>(
"releasePointerCapture", *m_capturedPointerId);
869 m_capturedPointerId = std::nullopt;
880 switch (event.type) {
881 case EventType::PointerDown:
882 m_capturedPointerId = event.pointerId;
883 m_window.call<
void>(
"setPointerCapture", event.pointerId);
886 if (!window()->flags().testFlag(Qt::WindowDoesNotAcceptFocus)
887 && QGuiApplication::focusWindow() != window()) {
888 QWindow *win = window();
889 while (!win->isTopLevel())
890 win = win->parent(QWindow::ExcludeTransients);
891 win->requestActivate();
896 event.webEvent.call<
void>(
"preventDefault");
900 releasePointerGrab(event);
906 const bool eventAccepted = deliverPointerEvent(event);
907 if (!eventAccepted && event.type == EventType::PointerDown)
908 QGuiApplicationPrivate::instance()->closeAllPopups();
911 event.webEvent.call<
void>(
"preventDefault");
912 event.webEvent.call<
void>(
"stopPropagation");
922 const QPointF targetPointClippedToScreen(
923 qBound(geometryF.left(), pointInScreen.x(), geometryF.right()),
924 qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom()));
927 const QEvent::Type eventType =
930 return eventType != QEvent::None
931 && QWindowSystemInterface::handleMouseEvent(
932 window(), QWasmIntegration::getTimestamp(),
933 window()->mapFromGlobal(targetPointClippedToScreen),
934 targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
935 eventType, event.modifiers);
940 switch (event.type) {
943 pressure = event.pressure;
952 qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
953 qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
955 qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
956 return QWindowSystemInterface::handleTabletEvent(
957 window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(),
958 window()->mapFromGlobal(targetPointClippedToScreen),
959 targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
960 event.tangentialPressure, rotation, event.modifiers);
963 QWindowSystemInterface::TouchPoint *touchPoint;
965 QPointF pointInTargetWindowCoords =
966 QPointF(window()->mapFromGlobal(targetPointClippedToScreen));
967 QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(),
968 pointInTargetWindowCoords.y() / window()->height());
970 const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
971 if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
972 touchPoint = &tp.value();
974 touchPoint = &m_pointerIdToTouchPoints
975 .insert(event.pointerId, QWindowSystemInterface::TouchPoint())
983 touchPoint->state = QEventPoint::State::Pressed;
986 const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition);
987 touchPoint->normalPosition = normalPosition;
988 touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height))
989 .translated(-event.width / 2, -event.height / 2);
990 touchPoint->pressure = event.pressure;
992 switch (event.type) {
993 case EventType::PointerUp:
994 touchPoint->state = QEventPoint::State::Released;
996 case EventType::PointerMove:
997 touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary
998 : QEventPoint::State::Updated);
1004 QList<QWindowSystemInterface::TouchPoint> touchPointList;
1005 touchPointList.reserve(m_pointerIdToTouchPoints.size());
1006 std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(),
1007 std::back_inserter(touchPointList),
1008 [](
const QWindowSystemInterface::TouchPoint &val) {
return val; });
1010 if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
1011 m_pointerIdToTouchPoints.remove(event.pointerId);
1013 return event.type == EventType::PointerCancel
1014 ? QWindowSystemInterface::handleTouchCancelEvent(
1015 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
1017 : QWindowSystemInterface::handleTouchEvent(
1018 window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(),
1019 touchPointList, event.modifiers);
1025 event.call<
void>(
"preventDefault");
1031 const int scrollFactor = -([&event]() {
1045 return QWindowSystemInterface::handleWheelEvent(
1046 window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
1047 pointInScreen, (event.delta * scrollFactor).toPoint(),
1048 (event.delta * scrollFactor).toPoint(), event.modifiers, Qt::NoScrollPhase,
1049 Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
1053Qt::WindowFlags
QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags)
const
1055 if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
1056 if (flags.testFlag(Qt::Window)) {
1057 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1058 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
1060 if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
1061 flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1063 if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
1064 flags |= Qt::FramelessWindowHint;
1069bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags)
const
1077 if (flags.testFlag(Qt::Tool) ||
1078 flags.testFlag(Qt::SplashScreen) ||
1079 flags.testFlag(Qt::ToolTip) ||
1080 flags.testFlag(Qt::Popup))
1088QWasmWindowStack<>::PositionPreference
QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
const
1090 flags = fixTopLevelWindowFlags(flags);
1092 if (flags.testFlag(Qt::WindowStaysOnTopHint))
1093 return QWasmWindowStack<>::PositionPreference::StayOnTop;
1094 if (flags.testFlag(Qt::WindowStaysOnBottomHint))
1095 return QWasmWindowStack<>::PositionPreference::StayOnBottom;
1096 if (shouldBeAboveTransientParentFlags(flags))
1097 return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
1098 return QWasmWindowStack<>::PositionPreference::Regular;
1102QWasmInputContext *
QWasmWindow::activeWasmInputContext()
const
1107 if (QWasmAccessibility::isEnabled())
1110 return inputContext && inputContext->isActive() ? inputContext :
nullptr;
1115 return m_normalGeometry;
1120 return screen()->devicePixelRatio();
1130 return !m_flags.testFlag(Qt::FramelessWindowHint);
1135 return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
1136 && !windowIsPopupType(m_flags) && !parent();
1141 return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
1146 return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
1151 return !m_state.testFlag(Qt::WindowMaximized) && m_flags.testFlag(Qt::WindowMaximizeButtonHint);
1154bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags)
const
1156 if (flags.testFlag(Qt::Tool))
1159 return (flags.testFlag(Qt::Popup));
1164 QWindow *modalWindow;
1165 if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
1181 if (QWasmAccessibility::isEnabled())
1184 emscripten::val &element = target == InputFocus ? m_inputElement : m_focusHelper;
1185 element.call<
void>(
"focus");
1190 m_focusHelper.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1191 m_inputElement.call<
void>(
"setAttribute", std::string(
"aria-hidden"), std::string(
"true"));
1202 switch (event->type()) {
1203 case QEvent::WindowBlocked:
1204 m_decoratedWindow[
"classList"].call<
void>(
"add", emscripten::val(
"blocked"));
1206 case QEvent::WindowUnblocked:;
1207 m_decoratedWindow[
"classList"].call<
void>(
"remove", emscripten::val(
"blocked"));
1210 return QPlatformWindow::windowEvent(event);
1216 if (region.isEmpty()) {
1217 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(
""));
1221 std::ostringstream cssClipPath;
1222 cssClipPath <<
"path('";
1223 for (
const auto &rect : region) {
1224 const auto cssRect = rect.adjusted(0, 0, 1, 1);
1225 cssClipPath <<
"M " << cssRect.left() <<
" " << cssRect.top() <<
" ";
1226 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.top() <<
" ";
1227 cssClipPath <<
"L " << cssRect.right() <<
" " << cssRect.bottom() <<
" ";
1228 cssClipPath <<
"L " << cssRect.left() <<
" " << cssRect.bottom() <<
" z ";
1230 cssClipPath <<
"')";
1231 m_decoratedWindow[
"style"].set(
"clipPath", emscripten::val(cssClipPath.str()));
1234void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
1236 Q_UNUSED(newTransientParent);
1238 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1239 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1240 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1245 const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
1246 QWasmWindowTreeNode::onParentChanged(parentNode(),
nullptr, positionPreference);
1247 QWasmWindowTreeNode::onParentChanged(
nullptr, parentNode(), positionPreference);
1254 setWindowFlags(window()->flags());
1256 commitParent(parentNode());
1261 return "!qtwindow" +
std::to_string(m_winId);
1282 QWasmWindowStack<>::PositionPreference positionPreference)
1285 previous->containerElement().call<
void>(
"removeChild", m_decoratedWindow);
1287 current->containerElement().call<
void>(
"appendChild", m_decoratedWindow);
1288 QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
1297 const auto state = window()->windowState();
1298 const bool isMaxFull = state & (Qt::WindowMaximized | Qt::WindowFullScreen);
1299 if (current == screen && screen->topLevelWindowCount() == 1 && isMaxFull)
1300 window()->setFlag(Qt::WindowStaysOnBottomHint);
QRect window() const
Returns the window rectangle.
void onWindowAdded(QWasmWindow *window)
void onWindowRemoved(QWasmWindow *window)
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