diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt index 2c9e3ec8675..4a669a84e31 100644 --- a/src/plugins/platforms/wasm/CMakeLists.txt +++ b/src/plugins/platforms/wasm/CMakeLists.txt @@ -30,7 +30,6 @@ qt_internal_add_plugin(QWasmIntegrationPlugin qwasmservices.cpp qwasmservices.h qwasmtheme.cpp qwasmtheme.h qwasmwindow.cpp qwasmwindow.h - qwasmwindowclientarea.cpp qwasmwindowclientarea.h qwasmwindowtreenode.cpp qwasmwindowtreenode.h qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h qwasminputcontext.cpp qwasminputcontext.h diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index fa3309f252a..036de1514bd 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -16,13 +16,13 @@ #include "qwasmintegration.h" #include "qwasmkeytranslator.h" #include "qwasmwindow.h" -#include "qwasmwindowclientarea.h" #include "qwasmscreen.h" #include "qwasmcompositor.h" #include "qwasmevent.h" #include "qwasmeventdispatcher.h" #include "qwasmaccessibility.h" #include "qwasmclipboard.h" +#include "qwasmdrag.h" #include #include @@ -65,8 +65,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, m_nonClientArea = std::make_unique(this, m_decoratedWindow); m_nonClientArea->titleBar()->setTitle(window()->title()); - m_clientArea = std::make_unique(this, compositor->screen(), m_window); - m_window.set("className", "qt-window"); m_decoratedWindow.call("appendChild", m_window); @@ -100,12 +98,64 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, m_flags = window()->flags(); + registerEventHandlers(); + + setParent(parent()); +} + +void QWasmWindow::registerEventHandlers() +{ + m_pointerDownCallback = std::make_unique(m_window, "pointerdown", + [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); } + ); + m_pointerMoveCallback = std::make_unique(m_window, "pointermove", + [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); } + ); + m_pointerUpCallback = std::make_unique(m_window, "pointerup", + [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); } + ); + m_pointerCancelCallback = std::make_unique(m_window, "pointercancel", + [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); } + ); m_pointerEnterCallback = std::make_unique(m_window, "pointerenter", - [this](emscripten::val event) { this->handlePointerEvent(PointerEvent(EventType::PointerEnter, event)); } + [this](emscripten::val event) { this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerEnter, event)); } ); m_pointerLeaveCallback = std::make_unique(m_window, "pointerleave", - [this](emscripten::val event) { this->handlePointerEvent(PointerEvent(EventType::PointerLeave, event)); } + [this](emscripten::val event) { this->handlePointerEnterLeaveEvent(PointerEvent(EventType::PointerLeave, event)); } ); + + m_window.call("setAttribute", emscripten::val("draggable"), emscripten::val("true")); + m_dragStartCallback = std::make_unique(m_window, "dragstart", + [this](emscripten::val event) { + DragEvent dragEvent(EventType::DragStart, event, window()); + QWasmDrag::instance()->onNativeDragStarted(&dragEvent); + } + ); + m_dragOverCallback = std::make_unique(m_window, "dragover", + [this](emscripten::val event) { + DragEvent dragEvent(EventType::DragOver, event, window()); + QWasmDrag::instance()->onNativeDragOver(&dragEvent); + } + ); + m_dropCallback = std::make_unique(m_window, "drop", + [this](emscripten::val event) { + DragEvent dragEvent(EventType::Drop, event, window()); + QWasmDrag::instance()->onNativeDrop(&dragEvent); + } + ); + m_dragEndCallback = std::make_unique(m_window, "dragend", + [this](emscripten::val event) { + DragEvent dragEvent(EventType::DragEnd, event, window()); + QWasmDrag::instance()->onNativeDragFinished(&dragEvent); + } + ); + m_dragLeaveCallback = std::make_unique(m_window, "dragleave", + [this](emscripten::val event) { + DragEvent dragEvent(EventType::DragLeave, event, window()); + QWasmDrag::instance()->onNativeDragLeave(&dragEvent); + } + ); + m_wheelEventCallback = std::make_unique( m_window, "wheel", [this](emscripten::val event) { this->handleWheelEvent(event); }); @@ -123,8 +173,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, [this](emscripten::val event) { this->handleKeyEvent(KeyEvent(EventType::KeyDown, event, m_deadKeySupport)); }); m_keyUpCallback =std::make_unique(m_window, "keyup", [this](emscripten::val event) {this->handleKeyEvent(KeyEvent(EventType::KeyUp, event, m_deadKeySupport)); }); - - setParent(parent()); } QWasmWindow::~QWasmWindow() @@ -586,13 +634,13 @@ bool QWasmWindow::processKeyForInputContext(const KeyEvent &event) return result; } -void QWasmWindow::handlePointerEvent(const PointerEvent &event) +void QWasmWindow::handlePointerEnterLeaveEvent(const PointerEvent &event) { - if (processPointer(event)) + if (processPointerEnterLeave(event)) event.webEvent.call("preventDefault"); } -bool QWasmWindow::processPointer(const PointerEvent &event) +bool QWasmWindow::processPointerEnterLeave(const PointerEvent &event) { if (event.pointerType != PointerType::Mouse && event.pointerType != PointerType::Pen) return false; @@ -615,6 +663,136 @@ bool QWasmWindow::processPointer(const PointerEvent &event) return false; } +void QWasmWindow::processPointer(const PointerEvent &event) +{ + switch (event.type) { + case EventType::PointerDown: + m_window.call("setPointerCapture", event.pointerId); + if ((window()->flags() & Qt::WindowDoesNotAcceptFocus) + != Qt::WindowDoesNotAcceptFocus + && window()->isTopLevel()) + window()->requestActivate(); + break; + case EventType::PointerUp: + m_window.call("releasePointerCapture", event.pointerId); + break; + default: + break; + }; + + const bool eventAccepted = deliverPointerEvent(event); + if (!eventAccepted && event.type == EventType::PointerDown) + QGuiApplicationPrivate::instance()->closeAllPopups(); + event.webEvent.call("preventDefault"); + event.webEvent.call("stopPropagation"); +} + +bool QWasmWindow::deliverPointerEvent(const PointerEvent &event) +{ + const auto pointInScreen = platformScreen()->mapFromLocal( + dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint)); + + const auto geometryF = platformScreen()->geometry().toRectF(); + const QPointF targetPointClippedToScreen( + qBound(geometryF.left(), pointInScreen.x(), geometryF.right()), + qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom())); + + if (event.pointerType == PointerType::Mouse) { + const QEvent::Type eventType = + MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client); + + return eventType != QEvent::None + && QWindowSystemInterface::handleMouseEvent( + window(), QWasmIntegration::getTimestamp(), + window()->mapFromGlobal(targetPointClippedToScreen), + targetPointClippedToScreen, event.mouseButtons, event.mouseButton, + eventType, event.modifiers); + } + + if (event.pointerType == PointerType::Pen) { + qreal pressure; + switch (event.type) { + case EventType::PointerDown : + case EventType::PointerMove : + pressure = event.pressure; + break; + case EventType::PointerUp : + pressure = 0.0; + break; + default: + return false; + } + // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60. + qreal xTilt = qBound(-60.0, event.tiltX, 60.0); + qreal yTilt = qBound(-60.0, event.tiltY, 60.0); + // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value. + qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist; + return QWindowSystemInterface::handleTabletEvent( + window(), QWasmIntegration::getTimestamp(), platformScreen()->tabletDevice(), + window()->mapFromGlobal(targetPointClippedToScreen), + targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt, + event.tangentialPressure, rotation, event.modifiers); + } + + QWindowSystemInterface::TouchPoint *touchPoint; + + QPointF pointInTargetWindowCoords = + QPointF(window()->mapFromGlobal(targetPointClippedToScreen)); + QPointF normalPosition(pointInTargetWindowCoords.x() / window()->width(), + pointInTargetWindowCoords.y() / window()->height()); + + const auto tp = m_pointerIdToTouchPoints.find(event.pointerId); + if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) { + touchPoint = &tp.value(); + } else { + touchPoint = &m_pointerIdToTouchPoints + .insert(event.pointerId, QWindowSystemInterface::TouchPoint()) + .value(); + + // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent() + // will not synthesize mouse events for touch points with negative id; use the absolute value for + // the touch point id. + touchPoint->id = qAbs(event.pointerId); + + touchPoint->state = QEventPoint::State::Pressed; + } + + const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition); + touchPoint->normalPosition = normalPosition; + touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height)) + .translated(-event.width / 2, -event.height / 2); + touchPoint->pressure = event.pressure; + + switch (event.type) { + case EventType::PointerUp: + touchPoint->state = QEventPoint::State::Released; + break; + case EventType::PointerMove: + touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary + : QEventPoint::State::Updated); + break; + default: + break; + } + + QList touchPointList; + touchPointList.reserve(m_pointerIdToTouchPoints.size()); + std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(), + std::back_inserter(touchPointList), + [](const QWindowSystemInterface::TouchPoint &val) { return val; }); + + if (event.type == EventType::PointerUp) + m_pointerIdToTouchPoints.remove(event.pointerId); + + return event.type == EventType::PointerCancel + ? QWindowSystemInterface::handleTouchCancelEvent( + window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(), + event.modifiers) + : QWindowSystemInterface::handleTouchEvent( + window(), QWasmIntegration::getTimestamp(), platformScreen()->touchDevice(), + touchPointList, event.modifiers); +} + void QWasmWindow::handleWheelEvent(const emscripten::val &event) { if (processWheel(WheelEvent(EventType::Wheel, event))) diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index c503f9f69eb..f1789a6dab1 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -5,21 +5,21 @@ #define QWASMWINDOW_H #include "qwasmintegration.h" -#include -#include -#include #include "qwasmbackingstore.h" #include "qwasmscreen.h" #include "qwasmcompositor.h" #include "qwasmwindownonclientarea.h" #include "qwasmwindowstack.h" #include "qwasmwindowtreenode.h" +#include "qwasmevent.h" #include -#include "QtGui/qopenglcontext.h" -#include +#include +#include +#include #include +#include #include @@ -29,7 +29,6 @@ namespace qstdweb { class EventCallback; } -class ClientArea; struct KeyEvent; struct PointerEvent; class QWasmDeadKeySupport; @@ -49,6 +48,8 @@ public: static QWasmWindow *fromWindow(QWindow *window); QSurfaceFormat format() const override; + void registerEventHandlers(); + void paint(); void setZOrder(int order); void setWindowCursor(QByteArray cssCursorName); @@ -126,8 +127,10 @@ private: bool processKey(const KeyEvent &event); void handleKeyForInputContextEvent(EventType eventType, const emscripten::val &event); bool processKeyForInputContext(const KeyEvent &event); - void handlePointerEvent(const PointerEvent &event); - bool processPointer(const PointerEvent &event); + void handlePointerEnterLeaveEvent(const PointerEvent &event); + bool processPointerEnterLeave(const PointerEvent &event); + void processPointer(const PointerEvent &event); + bool deliverPointerEvent(const PointerEvent &event); void handleWheelEvent(const emscripten::val &event); bool processWheel(const WheelEvent &event); @@ -144,7 +147,6 @@ private: emscripten::val m_context2d = emscripten::val::undefined(); std::unique_ptr m_nonClientArea; - std::unique_ptr m_clientArea; QWasmWindowTreeNode *m_commitedParent = nullptr; @@ -153,13 +155,23 @@ private: std::unique_ptr m_keyDownCallbackForInputContext; std::unique_ptr m_keyUpCallbackForInputContext; + std::unique_ptr m_pointerDownCallback; + std::unique_ptr m_pointerMoveCallback; + std::unique_ptr m_pointerUpCallback; + std::unique_ptr m_pointerCancelCallback; std::unique_ptr m_pointerLeaveCallback; std::unique_ptr m_pointerEnterCallback; + std::unique_ptr m_dragOverCallback; + std::unique_ptr m_dragStartCallback; + std::unique_ptr m_dragEndCallback; std::unique_ptr m_dropCallback; + std::unique_ptr m_dragLeaveCallback; std::unique_ptr m_wheelEventCallback; + QMap m_pointerIdToTouchPoints; + Qt::WindowStates m_state = Qt::WindowNoState; Qt::WindowStates m_previousWindowState = Qt::WindowNoState; diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp deleted file mode 100644 index 4403740fa47..00000000000 --- a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only - -#include "qwasmwindowclientarea.h" - -#include "qwasmdom.h" -#include "qwasmevent.h" -#include "qwasmscreen.h" -#include "qwasmwindow.h" -#include "qwasmdrag.h" - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -ClientArea::ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element) - : m_screen(screen), m_window(window), m_element(element) -{ - m_pointerDownCallback = std::make_unique(element, "pointerdown", - [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerDown, event)); } - ); - m_pointerMoveCallback = std::make_unique(element, "pointermove", - [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerMove, event)); } - ); - m_pointerUpCallback = std::make_unique(element, "pointerup", - [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerUp, event)); } - ); - m_pointerCancelCallback = std::make_unique(element, "pointercancel", - [this](emscripten::val event){ processPointer(PointerEvent(EventType::PointerCancel, event)); } - ); - - element.call("setAttribute", emscripten::val("draggable"), emscripten::val("true")); - m_dragStartCallback = std::make_unique(element, "dragstart", - [this](emscripten::val event) { - DragEvent dragEvent(EventType::DragStart, event, m_window->window()); - QWasmDrag::instance()->onNativeDragStarted(&dragEvent); - } - ); - m_dragOverCallback = std::make_unique(element, "dragover", - [this](emscripten::val event) { - DragEvent dragEvent(EventType::DragOver, event, m_window->window()); - QWasmDrag::instance()->onNativeDragOver(&dragEvent); - } - ); - m_dropCallback = std::make_unique(element, "drop", - [this](emscripten::val event) { - DragEvent dragEvent(EventType::Drop, event, m_window->window()); - QWasmDrag::instance()->onNativeDrop(&dragEvent); - } - ); - m_dragEndCallback = std::make_unique(element, "dragend", - [this](emscripten::val event) { - DragEvent dragEvent(EventType::DragEnd, event, m_window->window()); - QWasmDrag::instance()->onNativeDragFinished(&dragEvent); - } - ); - m_dragLeaveCallback = std::make_unique(element, "dragleave", - [this](emscripten::val event) { - DragEvent dragEvent(EventType::DragLeave, event, m_window->window()); - QWasmDrag::instance()->onNativeDragLeave(&dragEvent); - } - ); -} - -void ClientArea::processPointer(const PointerEvent &event) -{ - switch (event.type) { - case EventType::PointerDown: - m_element.call("setPointerCapture", event.pointerId); - if ((m_window->window()->flags() & Qt::WindowDoesNotAcceptFocus) - != Qt::WindowDoesNotAcceptFocus - && m_window->window()->isTopLevel()) - m_window->window()->requestActivate(); - break; - case EventType::PointerUp: - m_element.call("releasePointerCapture", event.pointerId); - break; - default: - break; - }; - - const bool eventAccepted = deliverEvent(event); - if (!eventAccepted && event.type == EventType::PointerDown) - QGuiApplicationPrivate::instance()->closeAllPopups(); - event.webEvent.call("preventDefault"); - event.webEvent.call("stopPropagation"); -} - -bool ClientArea::deliverEvent(const PointerEvent &event) -{ - const auto pointInScreen = m_screen->mapFromLocal( - dom::mapPoint(event.target(), m_screen->element(), event.localPoint)); - - const auto geometryF = m_screen->geometry().toRectF(); - const QPointF targetPointClippedToScreen( - qBound(geometryF.left(), pointInScreen.x(), geometryF.right()), - qBound(geometryF.top(), pointInScreen.y(), geometryF.bottom())); - - if (event.pointerType == PointerType::Mouse) { - const QEvent::Type eventType = - MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client); - - return eventType != QEvent::None - && QWindowSystemInterface::handleMouseEvent( - m_window->window(), QWasmIntegration::getTimestamp(), - m_window->window()->mapFromGlobal(targetPointClippedToScreen), - targetPointClippedToScreen, event.mouseButtons, event.mouseButton, - eventType, event.modifiers); - } - - if (event.pointerType == PointerType::Pen) { - qreal pressure; - switch (event.type) { - case EventType::PointerDown : - case EventType::PointerMove : - pressure = event.pressure; - break; - case EventType::PointerUp : - pressure = 0.0; - break; - default: - return false; - } - // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60. - qreal xTilt = qBound(-60.0, event.tiltX, 60.0); - qreal yTilt = qBound(-60.0, event.tiltY, 60.0); - // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value. - qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist; - return QWindowSystemInterface::handleTabletEvent( - m_window->window(), QWasmIntegration::getTimestamp(), m_screen->tabletDevice(), - m_window->window()->mapFromGlobal(targetPointClippedToScreen), - targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt, - event.tangentialPressure, rotation, event.modifiers); - } - - QWindowSystemInterface::TouchPoint *touchPoint; - - QPointF pointInTargetWindowCoords = - QPointF(m_window->window()->mapFromGlobal(targetPointClippedToScreen)); - QPointF normalPosition(pointInTargetWindowCoords.x() / m_window->window()->width(), - pointInTargetWindowCoords.y() / m_window->window()->height()); - - const auto tp = m_pointerIdToTouchPoints.find(event.pointerId); - if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) { - touchPoint = &tp.value(); - } else { - touchPoint = &m_pointerIdToTouchPoints - .insert(event.pointerId, QWindowSystemInterface::TouchPoint()) - .value(); - - // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent() - // will not synthesize mouse events for touch points with negative id; use the absolute value for - // the touch point id. - touchPoint->id = qAbs(event.pointerId); - - touchPoint->state = QEventPoint::State::Pressed; - } - - const bool stationaryTouchPoint = (normalPosition == touchPoint->normalPosition); - touchPoint->normalPosition = normalPosition; - touchPoint->area = QRectF(targetPointClippedToScreen, QSizeF(event.width, event.height)) - .translated(-event.width / 2, -event.height / 2); - touchPoint->pressure = event.pressure; - - switch (event.type) { - case EventType::PointerUp: - touchPoint->state = QEventPoint::State::Released; - break; - case EventType::PointerMove: - touchPoint->state = (stationaryTouchPoint ? QEventPoint::State::Stationary - : QEventPoint::State::Updated); - break; - default: - break; - } - - QList touchPointList; - touchPointList.reserve(m_pointerIdToTouchPoints.size()); - std::transform(m_pointerIdToTouchPoints.begin(), m_pointerIdToTouchPoints.end(), - std::back_inserter(touchPointList), - [](const QWindowSystemInterface::TouchPoint &val) { return val; }); - - if (event.type == EventType::PointerUp) - m_pointerIdToTouchPoints.remove(event.pointerId); - - return event.type == EventType::PointerCancel - ? QWindowSystemInterface::handleTouchCancelEvent( - m_window->window(), QWasmIntegration::getTimestamp(), m_screen->touchDevice(), - event.modifiers) - : QWindowSystemInterface::handleTouchEvent( - m_window->window(), QWasmIntegration::getTimestamp(), m_screen->touchDevice(), - touchPointList, event.modifiers); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.h b/src/plugins/platforms/wasm/qwasmwindowclientarea.h deleted file mode 100644 index 22f8686c68a..00000000000 --- a/src/plugins/platforms/wasm/qwasmwindowclientarea.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only - -#ifndef QWASMWINDOWCLIENTAREA_H -#define QWASMWINDOWCLIENTAREA_H - -#include -#include -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -namespace qstdweb { -class EventCallback; -} - -struct PointerEvent; -class QWasmScreen; -class QWasmWindow; - -class ClientArea -{ -public: - ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element); - -private: - void processPointer(const PointerEvent &event); - bool deliverEvent(const PointerEvent &event); - - std::unique_ptr m_pointerDownCallback; - std::unique_ptr m_pointerMoveCallback; - std::unique_ptr m_pointerUpCallback; - std::unique_ptr m_pointerCancelCallback; - - std::unique_ptr m_dragOverCallback; - std::unique_ptr m_dragStartCallback; - std::unique_ptr m_dragEndCallback; - std::unique_ptr m_dropCallback; - std::unique_ptr m_dragLeaveCallback; - - QMap m_pointerIdToTouchPoints; - - QWasmScreen *m_screen; - QWasmWindow *m_window; - emscripten::val m_element; -}; - -QT_END_NAMESPACE -#endif // QWASMWINDOWNONCLIENTAREA_H