From 6501b85d3818f0edcba1c0230d3d57bfb79da818 Mon Sep 17 00:00:00 2001 From: Mikolaj Boc Date: Tue, 20 Dec 2022 15:56:49 +0100 Subject: [PATCH] Handle the mouse events in the window itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is now not the screen that handles all of the events and relays them to individual windows, but the window elements themselves. This allows us to get rid of manual window targeting logic and let the browser do its job. Fixes: QTBUG-107217 Change-Id: I4dc5a74b1343f027f72c1da4623b99cd28bfbb38 Reviewed-by: Morten Johan Sørvig (cherry picked from commit c15a8750bcce3d4dabeebcc8bb4c15db31c7f637) Reviewed-by: Mikołaj Boc --- src/plugins/platforms/wasm/CMakeLists.txt | 1 + .../platforms/wasm/qwasmcompositor.cpp | 191 +----------------- src/plugins/platforms/wasm/qwasmcompositor.h | 19 -- src/plugins/platforms/wasm/qwasmcssstyle.cpp | 4 - src/plugins/platforms/wasm/qwasmevent.cpp | 2 +- src/plugins/platforms/wasm/qwasmevent.h | 2 +- src/plugins/platforms/wasm/qwasmwindow.cpp | 55 +++-- src/plugins/platforms/wasm/qwasmwindow.h | 17 +- .../platforms/wasm/qwasmwindowclientarea.cpp | 93 +++++++++ .../platforms/wasm/qwasmwindowclientarea.h | 42 ++++ .../wasm/qwasmwindownonclientarea.cpp | 26 +-- .../platforms/wasm/qwasmwindownonclientarea.h | 4 +- 12 files changed, 215 insertions(+), 241 deletions(-) create mode 100644 src/plugins/platforms/wasm/qwasmwindowclientarea.cpp create mode 100644 src/plugins/platforms/wasm/qwasmwindowclientarea.h diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt index 17acc402893..15892617ca2 100644 --- a/src/plugins/platforms/wasm/CMakeLists.txt +++ b/src/plugins/platforms/wasm/CMakeLists.txt @@ -35,6 +35,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin qwasmstylepixmaps_p.h qwasmtheme.cpp qwasmtheme.h qwasmwindow.cpp qwasmwindow.h + qwasmwindowclientarea.cpp qwasmwindowclientarea.h qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h qwasminputcontext.cpp qwasminputcontext.h qwasmdrag.cpp qwasmdrag.h diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index ebcec4fa360..70938b323bc 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -60,8 +60,6 @@ QWasmCompositor::QWasmCompositor(QWasmScreen *screen) QWasmCompositor::~QWasmCompositor() { - m_windowUnderMouse.clear(); - if (m_requestAnimationFrameId != -1) emscripten_cancel_animation_frame(m_requestAnimationFrameId); @@ -79,8 +77,6 @@ void QWasmCompositor::deregisterEventHandlers() emscripten_set_keydown_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_keyup_callback(screenElementSelector.constData(), 0, 0, NULL); - emscripten_set_focus_callback(screenElementSelector.constData(), 0, 0, NULL); - emscripten_set_wheel_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL); @@ -116,26 +112,6 @@ void QWasmCompositor::initEventHandlers() emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture, &keyboard_cb); - val screenElement = screen()->element(); - const auto callback = std::function([this](emscripten::val event) { - if (processPointer(*PointerEvent::fromWeb(event))) - event.call("preventDefault"); - }); - - m_pointerDownCallback = - std::make_unique(screenElement, "pointerdown", callback); - m_pointerMoveCallback = - std::make_unique(screenElement, "pointermove", callback); - m_pointerUpCallback = - std::make_unique(screenElement, "pointerup", callback); - m_pointerEnterCallback = - std::make_unique(screenElement, "pointerenter", callback); - m_pointerLeaveCallback = - std::make_unique(screenElement, "pointerleave", callback); - - emscripten_set_focus_callback(screenElementSelector.constData(), (void *)this, UseCapture, - &focus_cb); - emscripten_set_wheel_callback(screenElementSelector.constData(), (void *)this, UseCapture, &wheel_cb); @@ -148,10 +124,10 @@ void QWasmCompositor::initEventHandlers() emscripten_set_touchcancel_callback(screenElementSelector.constData(), (void *)this, UseCapture, &touchCallback); - screenElement.call("addEventListener", std::string("drop"), - val::module_property("qtDrop"), val(true)); - screenElement.set("data-qtdropcontext", // ? unique - emscripten::val(quintptr(reinterpret_cast(screen())))); + screen()->element().call("addEventListener", std::string("drop"), + val::module_property("qtDrop"), val(true)); + screen()->element().set("data-qtdropcontext", // ? unique + emscripten::val(quintptr(reinterpret_cast(screen())))); } void QWasmCompositor::addWindow(QWasmWindow *window) @@ -166,8 +142,6 @@ void QWasmCompositor::removeWindow(QWasmWindow *window) { m_requestUpdateWindows.remove(window); m_windowStack.removeWindow(window); - if (m_lastMouseTargetWindow == window->window()) - m_lastMouseTargetWindow = nullptr; if (m_windowStack.topWindow()) m_windowStack.topWindow()->requestActivateWindow(); @@ -348,15 +322,6 @@ int QWasmCompositor::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *k return static_cast(wasmCompositor->processKeyboard(eventType, keyEvent)); } -int QWasmCompositor::focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData) -{ - Q_UNUSED(eventType) - Q_UNUSED(focusEvent) - Q_UNUSED(userData) - - return 0; -} - int QWasmCompositor::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) { QWasmCompositor *compositor = (QWasmCompositor *) userData; @@ -369,112 +334,6 @@ int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *to return static_cast(compositor->processTouch(eventType, touchEvent)); } -bool QWasmCompositor::processPointer(const PointerEvent& event) -{ - if (event.pointerType != PointerType::Mouse) - return false; - - const auto pointInScreen = screen()->mapFromLocal(event.localPoint); - - QWindow *const targetWindow = ([this, pointInScreen]() -> QWindow * { - auto *targetWindow = m_mouseCaptureWindow != nullptr - ? m_mouseCaptureWindow.get() - : windowAt(pointInScreen, 5); - - return targetWindow ? targetWindow : m_lastMouseTargetWindow.get(); - })(); - if (!targetWindow) - return false; - m_lastMouseTargetWindow = targetWindow; - - const QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(pointInScreen); - const bool pointerIsWithinTargetWindowBounds = targetWindow->geometry().contains(pointInScreen); - - if (m_mouseInScreen && m_windowUnderMouse != targetWindow - && pointerIsWithinTargetWindowBounds) { - // delayed mouse enter - enterWindow(targetWindow, pointInTargetWindowCoords, pointInScreen); - m_windowUnderMouse = targetWindow; - } - - switch (event.type) { - case EventType::PointerDown: - { - screen()->element().call("setPointerCapture", event.pointerId); - - if (targetWindow) - targetWindow->requestActivate(); - - break; - } - case EventType::PointerUp: - { - screen()->element().call("releasePointerCapture", event.pointerId); - - break; - } - case EventType::PointerEnter: - processMouseEnter(nullptr); - break; - case EventType::PointerLeave: - processMouseLeave(); - break; - default: - break; - }; - - if (!pointerIsWithinTargetWindowBounds && event.mouseButtons.testFlag(Qt::NoButton)) { - leaveWindow(m_lastMouseTargetWindow); - } - - const bool eventAccepted = deliverEventToTarget(event, targetWindow); - if (!eventAccepted && event.type == EventType::PointerDown) - QGuiApplicationPrivate::instance()->closeAllPopups(); - return eventAccepted; -} - -bool QWasmCompositor::deliverEventToTarget(const PointerEvent &event, QWindow *eventTarget) -{ - Q_ASSERT(!m_mouseCaptureWindow || m_mouseCaptureWindow.get() == eventTarget); - - const auto pointInScreen = screen()->mapFromLocal(event.localPoint); - - const QPoint targetPointClippedToScreen( - std::max(screen()->geometry().left(), - std::min(screen()->geometry().right(), pointInScreen.x())), - std::max(screen()->geometry().top(), - std::min(screen()->geometry().bottom(), pointInScreen.y()))); - - bool deliveringToPreviouslyClickedWindow = false; - - if (!eventTarget) { - if (event.type != EventType::PointerUp || !m_lastMouseTargetWindow) - return false; - - eventTarget = m_lastMouseTargetWindow; - m_lastMouseTargetWindow = nullptr; - deliveringToPreviouslyClickedWindow = true; - } - - WindowArea windowArea = WindowArea::Client; - if (!deliveringToPreviouslyClickedWindow && !m_mouseCaptureWindow - && !eventTarget->geometry().contains(targetPointClippedToScreen)) { - if (!eventTarget->frameGeometry().contains(targetPointClippedToScreen)) - return false; - windowArea = WindowArea::NonClient; - } - - const QEvent::Type eventType = - MouseEvent::mouseEventTypeFromEventType(event.type, windowArea); - - return eventType != QEvent::None && - QWindowSystemInterface::handleMouseEvent( - eventTarget, QWasmIntegration::getTimestamp(), - eventTarget->mapFromGlobal(targetPointClippedToScreen), - targetPointClippedToScreen, event.mouseButtons, event.mouseButton, - eventType, event.modifiers); -} - bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *emKeyEvent) { constexpr bool ProceedToNativeEvent = false; @@ -525,9 +384,8 @@ bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wh scrollFactor = -scrollFactor; // Web scroll deltas are inverted from Qt deltas. Qt::KeyboardModifiers modifiers = KeyboardModifier::getForEvent(*mouseEvent); - QPoint targetPointInScreenElementCoords(mouseEvent->targetX, mouseEvent->targetY); QPoint targetPointInScreenCoords = - screen()->geometry().topLeft() + targetPointInScreenElementCoords; + screen()->mapFromLocal(QPoint(mouseEvent->targetX, mouseEvent->targetY)); QWindow *targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5); if (!targetWindow) @@ -559,9 +417,8 @@ bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *to const EmscriptenTouchPoint *touches = &touchEvent->touches[i]; - QPoint targetPointInScreenElementCoords(touches->targetX, touches->targetY); QPoint targetPointInScreenCoords = - screen()->geometry().topLeft() + targetPointInScreenElementCoords; + screen()->mapFromLocal(QPoint(touches->targetX, touches->targetY)); targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5); if (targetWindow == nullptr) @@ -628,39 +485,3 @@ bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *to return static_cast(accepted); } - -void QWasmCompositor::setCapture(QWasmWindow *window) -{ - Q_ASSERT(std::find(m_windowStack.begin(), m_windowStack.end(), window) != m_windowStack.end()); - m_mouseCaptureWindow = window->window(); -} - -void QWasmCompositor::releaseCapture() -{ - m_mouseCaptureWindow = nullptr; -} - -void QWasmCompositor::leaveWindow(QWindow *window) -{ - m_windowUnderMouse = nullptr; - QWindowSystemInterface::handleLeaveEvent(window); -} - -void QWasmCompositor::enterWindow(QWindow *window, const QPoint &pointInTargetWindowCoords, const QPoint &targetPointInScreenCoords) -{ - QWindowSystemInterface::handleEnterEvent(window, pointInTargetWindowCoords, targetPointInScreenCoords); -} - -bool QWasmCompositor::processMouseEnter(const EmscriptenMouseEvent *mouseEvent) -{ - Q_UNUSED(mouseEvent) - // mouse has entered the screen area - m_mouseInScreen = true; - return true; -} - -bool QWasmCompositor::processMouseLeave() -{ - m_mouseInScreen = false; - return true; -} diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 4d7773c4ecd..7845987e9fa 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -82,15 +82,10 @@ private: static int focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData); static int wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData); - bool processPointer(const PointerEvent& event); - bool deliverEventToTarget(const PointerEvent& event, QWindow *eventTarget); - static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData); bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent); bool processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent); - bool processMouseEnter(const EmscriptenMouseEvent *mouseEvent); - bool processMouseLeave(); bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent); void enterWindow(QWindow *window, const QPoint &localPoint, const QPoint &globalPoint); @@ -108,25 +103,11 @@ private: int m_requestAnimationFrameId = -1; bool m_inDeliverUpdateRequest = false; - QPointer m_lastMouseTargetWindow; - QPointer m_mouseCaptureWindow; - - std::unique_ptr m_pointerDownCallback; - std::unique_ptr m_pointerMoveCallback; - std::unique_ptr m_pointerUpCallback; - std::unique_ptr m_pointerLeaveCallback; - std::unique_ptr m_pointerEnterCallback; - std::unique_ptr m_touchDevice; QMap m_pressedTouchIds; - bool m_isResizeCursorDisplayed = false; - std::unique_ptr m_eventTranslator; - - bool m_mouseInScreen = false; - QPointer m_windowUnderMouse; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmcssstyle.cpp b/src/plugins/platforms/wasm/qwasmcssstyle.cpp index b6f2befc391..341bdf4f378 100644 --- a/src/plugins/platforms/wasm/qwasmcssstyle.cpp +++ b/src/plugins/platforms/wasm/qwasmcssstyle.cpp @@ -29,7 +29,6 @@ const char *Style = R"css( .qt-window { box-shadow: rgb(0 0 0 / 20%) 0px 10px 16px 0px, rgb(0 0 0 / 19%) 0px 6px 20px 0px; - pointer-events: none; position: absolute; background-color: lightgray; } @@ -41,7 +40,6 @@ const char *Style = R"css( .resize-outline { position: absolute; - pointer-events: all; display: none; } @@ -119,7 +117,6 @@ const char *Style = R"css( overflow: hidden; height: 18px; padding-bottom: 4px; - pointer-events: all; } .qt-window.has-title-bar .title-bar { @@ -189,7 +186,6 @@ const char *Style = R"css( } .title-bar .action-button { pointer-events: all; - align-self: end; } .qt-window.blocked div { diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp index 919ab7d7787..19730c2c685 100644 --- a/src/plugins/platforms/wasm/qwasmevent.cpp +++ b/src/plugins/platforms/wasm/qwasmevent.cpp @@ -39,7 +39,7 @@ std::optional PointerEvent::fromWeb(emscripten::val event) return std::nullopt; ret.type = *eventType; - ret.currentTarget = event["currentTarget"]; + ret.target = event["target"]; ret.pointerType = event["pointerType"].as() == "mouse" ? PointerType::Mouse : PointerType::Other; ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as()); diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h index 7fe68ce6c88..f9d6411d60d 100644 --- a/src/plugins/platforms/wasm/qwasmevent.h +++ b/src/plugins/platforms/wasm/qwasmevent.h @@ -110,7 +110,7 @@ QFlags getForEvent( struct Q_CORE_EXPORT Event { EventType type; - emscripten::val currentTarget = emscripten::val::undefined(); + emscripten::val target = emscripten::val::undefined(); }; struct Q_CORE_EXPORT MouseEvent : public Event diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index e84b2ddc7b3..aa229b5776a 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -12,6 +12,7 @@ #include "qwasmbase64iconstore.h" #include "qwasmdom.h" #include "qwasmwindow.h" +#include "qwasmwindowclientarea.h" #include "qwasmscreen.h" #include "qwasmstylepixmaps_p.h" #include "qwasmcompositor.h" @@ -25,6 +26,8 @@ #include +#include + QT_BEGIN_NAMESPACE Q_GUI_EXPORT int qt_defaultDpiX(); @@ -47,6 +50,8 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt m_nonClientArea = std::make_unique(this, m_qtWindow); m_nonClientArea->titleBar()->setTitle(window()->title()); + m_clientArea = std::make_unique(this, compositor->screen(), m_canvas); + m_qtWindow.call("appendChild", m_windowContents); m_canvas["classList"].call("add", emscripten::val("qt-window-content")); @@ -70,6 +75,16 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas); m_compositor->addWindow(this); + + const auto callback = std::function([this](emscripten::val event) { + if (processPointer(*PointerEvent::fromWeb(event))) + event.call("preventDefault"); + }); + + m_pointerEnterCallback = + std::make_unique(m_qtWindow, "pointerenter", callback); + m_pointerLeaveCallback = + std::make_unique(m_qtWindow, "pointerleave", callback); } QWasmWindow::~QWasmWindow() @@ -112,8 +127,8 @@ void QWasmWindow::onNonClientAreaInteraction() bool QWasmWindow::onNonClientEvent(const PointerEvent &event) { QPoint pointInScreen = platformScreen()->mapFromLocal( - dom::mapPoint(event.currentTarget, platformScreen()->element(), event.localPoint)); - return QWindowSystemInterface::handleMouseEvent( + dom::mapPoint(event.target, platformScreen()->element(), event.localPoint)); + return QWindowSystemInterface::handleMouseEvent( window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen), pointInScreen, event.mouseButtons, event.mouseButton, ([event]() { switch (event.type) { @@ -300,12 +315,6 @@ void QWasmWindow::propagateSizeHints() } } -bool QWasmWindow::startSystemResize(Qt::Edges) -{ - // TODO(mikolajboc): This can only be implemented if per-window events are up and running - return false; -} - void QWasmWindow::invalidate() { m_compositor->requestUpdateWindow(this); @@ -387,6 +396,29 @@ void QWasmWindow::applyWindowState() setGeometry(newGeom); } +bool QWasmWindow::processPointer(const PointerEvent &event) +{ + if (event.pointerType != PointerType::Mouse) + return false; + + switch (event.type) { + case EventType::PointerEnter: { + const auto pointInScreen = platformScreen()->mapFromLocal( + dom::mapPoint(event.target, platformScreen()->element(), event.localPoint)); + QWindowSystemInterface::handleEnterEvent( + window(), m_window->mapFromGlobal(pointInScreen), pointInScreen); + break; + } + case EventType::PointerLeave: + QWindowSystemInterface::handleLeaveEvent(window()); + break; + default: + break; + } + + return false; +} + QRect QWasmWindow::normalGeometry() const { return m_normalGeometry; @@ -431,11 +463,8 @@ void QWasmWindow::requestActivateWindow() bool QWasmWindow::setMouseGrabEnabled(bool grab) { - if (grab) - m_compositor->setCapture(this); - else - m_compositor->releaseCapture(); - return true; + Q_UNUSED(grab); + return false; } bool QWasmWindow::windowEvent(QEvent *event) diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index 35c2f63e633..5651495c741 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -20,6 +20,12 @@ QT_BEGIN_NAMESPACE +namespace qstdweb { +class EventCallback; +} + +class ClientArea; + class QWasmWindow final : public QPlatformWindow { public: @@ -59,7 +65,6 @@ public: bool setKeyboardGrabEnabled(bool) override { return false; } bool setMouseGrabEnabled(bool grab) final; bool windowEvent(QEvent *event) final; - bool startSystemResize(Qt::Edges edges) final; QWasmScreen *platformScreen() const; void setBackingStore(QWasmBackingStore *store) { m_backingStore = store; } @@ -78,6 +83,8 @@ private: bool hasTitleBar() const; void applyWindowState(); + bool processPointer(const PointerEvent &event); + QWindow *m_window = nullptr; QWasmCompositor *m_compositor = nullptr; QWasmBackingStore *m_backingStore = nullptr; @@ -92,13 +99,21 @@ private: emscripten::val m_context2d = emscripten::val::undefined(); std::unique_ptr m_nonClientArea; + std::unique_ptr m_clientArea; + + std::unique_ptr m_pointerLeaveCallback; + std::unique_ptr m_pointerEnterCallback; + std::unique_ptr m_pointerMoveCallback; Qt::WindowStates m_state = Qt::WindowNoState; Qt::WindowStates m_previousWindowState = Qt::WindowNoState; Qt::WindowFlags m_flags = Qt::Widget; + QPoint m_lastPointerMovePoint; + WId m_winId = 0; + bool m_wantCapture = false; bool m_hasTitle = false; bool m_needsCompositor = false; long m_requestAnimationFrameId = -1; diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp new file mode 100644 index 00000000000..e3e17baa1e9 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp @@ -0,0 +1,93 @@ +// 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 +#include + +#include + +QT_BEGIN_NAMESPACE + +ClientArea::ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element) + : m_screen(screen), m_window(window), m_element(element) +{ + const auto callback = std::function([this](emscripten::val event) { + if (processPointer(*PointerEvent::fromWeb(event))) + event.call("preventDefault"); + }); + + m_pointerDownCallback = + std::make_unique(element, "pointerdown", callback); + m_pointerMoveCallback = + std::make_unique(element, "pointermove", callback); + m_pointerUpCallback = std::make_unique(element, "pointerup", callback); +} + +bool ClientArea::processPointer(const PointerEvent &event) +{ + if (event.pointerType != PointerType::Mouse) + return false; + + const auto localScreenPoint = + dom::mapPoint(event.target, m_screen->element(), event.localPoint); + const auto pointInScreen = m_screen->mapFromLocal(localScreenPoint); + + const QPoint pointInTargetWindowCoords = m_window->mapFromGlobal(pointInScreen); + + switch (event.type) { + case EventType::PointerDown: { + m_element.call("setPointerCapture", event.pointerId); + m_window->window()->requestActivate(); + break; + } + case EventType::PointerUp: { + m_element.call("releasePointerCapture", event.pointerId); + break; + } + case EventType::PointerEnter:; + QWindowSystemInterface::handleEnterEvent( + m_window->window(), pointInTargetWindowCoords, pointInScreen); + break; + case EventType::PointerLeave: + QWindowSystemInterface::handleLeaveEvent(m_window->window()); + break; + default: + break; + }; + + const bool eventAccepted = deliverEvent(event); + if (!eventAccepted && event.type == EventType::PointerDown) + QGuiApplicationPrivate::instance()->closeAllPopups(); + return eventAccepted; +} + +bool ClientArea::deliverEvent(const PointerEvent &event) +{ + const auto pointInScreen = m_screen->mapFromLocal( + dom::mapPoint(event.target, m_screen->element(), event.localPoint)); + + const QPoint targetPointClippedToScreen( + std::max(m_screen->geometry().left(), + std::min(m_screen->geometry().right(), pointInScreen.x())), + std::max(m_screen->geometry().top(), + std::min(m_screen->geometry().bottom(), pointInScreen.y()))); + + 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); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.h b/src/plugins/platforms/wasm/qwasmwindowclientarea.h new file mode 100644 index 00000000000..f2fd115e25b --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.h @@ -0,0 +1,42 @@ +// 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 + +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: + bool processPointer(const PointerEvent &event); + bool deliverEvent(const PointerEvent &event); + + std::unique_ptr m_pointerDownCallback; + std::unique_ptr m_pointerMoveCallback; + std::unique_ptr m_pointerUpCallback; + + QWasmScreen *m_screen; + QWasmWindow *m_window; + emscripten::val m_element; +}; + +QT_END_NAMESPACE +#endif // QWASMWINDOWNONCLIENTAREA_H diff --git a/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp index 170cbbfa31a..304f678add4 100644 --- a/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp +++ b/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp @@ -55,14 +55,16 @@ void WebImageButton::setCallbacks(Callbacks callbacks) if (callbacks) { if (!m_webClickEventCallback) { m_webMouseDownEventCallback = std::make_unique( - m_containerElement, "mousedown", [this](emscripten::val event) { + m_containerElement, "pointerdown", [this](emscripten::val event) { event.call("preventDefault"); event.call("stopPropagation"); m_callbacks.onInteraction(); }); m_webClickEventCallback = std::make_unique( - m_containerElement, "click", - [this](emscripten::val) { m_callbacks.onClick(); }); + m_containerElement, "click", [this](emscripten::val event) { + m_callbacks.onClick(); + event.call("stopPropagation"); + }); } } else { m_webMouseDownEventCallback.reset(); @@ -104,12 +106,10 @@ Resizer::ResizerElement::ResizerElement(emscripten::val parentElement, Qt::Edges event.call("preventDefault"); event.call("stopPropagation"); }); - m_mouseDragEvent = std::make_unique( + m_mouseMoveEvent = std::make_unique( m_element, "pointermove", [this](emscripten::val event) { - if (onPointerMove(*PointerEvent::fromWeb(event))) { + if (onPointerMove(*PointerEvent::fromWeb(event))) event.call("preventDefault"); - event.call("stopPropagation"); - } }); m_mouseUpEvent = std::make_unique( m_element, "pointerup", [this](emscripten::val event) { @@ -193,7 +193,7 @@ void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event) m_currentResizeData.reset(new ResizeData{ .edges = resizeEdges, .originInScreenCoords = dom::mapPoint( - event.currentTarget, m_window->platformScreen()->element(), event.localPoint), + event.target, m_window->platformScreen()->element(), event.localPoint), }); const auto *window = m_window->window(); @@ -213,15 +213,12 @@ void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event) window->maximumHeight() - window->geometry().height())); m_currentResizeData->initialBounds = window->geometry(); - - // TODO(mikolajboc): Implement system resize - // .m_originInScreenCoords = m_systemDragInitData.lastMouseMovePoint, } void Resizer::continueResize(const PointerEvent &event) { - const auto pointInScreen = dom::mapPoint( - event.currentTarget, m_window->platformScreen()->element(), event.localPoint); + const auto pointInScreen = + dom::mapPoint(event.target, m_window->platformScreen()->element(), event.localPoint); const auto amount = pointInScreen - m_currentResizeData->originInScreenCoords; const QPoint cappedGrowVector( std::min(m_currentResizeData->maxGrow.x(), @@ -310,11 +307,10 @@ TitleBar::TitleBar(QWasmWindow *window, emscripten::val parentElement) event.call("preventDefault"); event.call("stopPropagation"); }); - m_mouseDragEvent = std::make_unique( + m_mouseMoveEvent = std::make_unique( m_element, "pointermove", [this](emscripten::val event) { if (onPointerMove(*PointerEvent::fromWeb(event))) { event.call("preventDefault"); - event.call("stopPropagation"); } }); m_mouseUpEvent = std::make_unique( diff --git a/src/plugins/platforms/wasm/qwasmwindownonclientarea.h b/src/plugins/platforms/wasm/qwasmwindownonclientarea.h index b561e8de785..18d1c63f4b3 100644 --- a/src/plugins/platforms/wasm/qwasmwindownonclientarea.h +++ b/src/plugins/platforms/wasm/qwasmwindownonclientarea.h @@ -137,7 +137,7 @@ public: Resizer *m_resizer; std::unique_ptr m_mouseDownEvent; - std::unique_ptr m_mouseDragEvent; + std::unique_ptr m_mouseMoveEvent; std::unique_ptr m_mouseUpEvent; }; @@ -203,7 +203,7 @@ private: QPoint m_lastMovePoint; std::unique_ptr m_mouseDownEvent; - std::unique_ptr m_mouseDragEvent; + std::unique_ptr m_mouseMoveEvent; std::unique_ptr m_mouseUpEvent; std::unique_ptr m_doubleClickEvent; };