diff options
-rw-r--r-- | src/plugins/platforms/wasm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmcompositor.cpp | 8 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmdrag.cpp | 78 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmdrag.h | 17 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmevent.cpp | 113 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmevent.h | 43 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmintegration.cpp | 6 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmintegration.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmwindow.cpp | 30 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmwindow.h | 13 |
10 files changed, 176 insertions, 137 deletions
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt index 8902597001..ade727423c 100644 --- a/src/plugins/platforms/wasm/CMakeLists.txt +++ b/src/plugins/platforms/wasm/CMakeLists.txt @@ -37,7 +37,6 @@ qt_internal_add_plugin(QWasmIntegrationPlugin qwasmwindowclientarea.cpp qwasmwindowclientarea.h qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h qwasminputcontext.cpp qwasminputcontext.h - qwasmdrag.cpp qwasmdrag.h qwasmwindowstack.cpp qwasmwindowstack.h DEFINES QT_EGL_NO_X11 diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index 70938b323b..0700d66a55 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -83,9 +83,6 @@ void QWasmCompositor::deregisterEventHandlers() emscripten_set_touchend_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_touchmove_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_touchcancel_callback(screenElementSelector.constData(), 0, 0, NULL); - - screen()->element().call<void>("removeEventListener", std::string("drop"), - val::module_property("qtDrop"), val(true)); } void QWasmCompositor::destroy() @@ -123,11 +120,6 @@ void QWasmCompositor::initEventHandlers() &touchCallback); emscripten_set_touchcancel_callback(screenElementSelector.constData(), (void *)this, UseCapture, &touchCallback); - - screen()->element().call<void>("addEventListener", std::string("drop"), - val::module_property("qtDrop"), val(true)); - screen()->element().set("data-qtdropcontext", // ? unique - emscripten::val(quintptr(reinterpret_cast<void *>(screen())))); } void QWasmCompositor::addWindow(QWasmWindow *window) diff --git a/src/plugins/platforms/wasm/qwasmdrag.cpp b/src/plugins/platforms/wasm/qwasmdrag.cpp deleted file mode 100644 index 144c30e0fb..0000000000 --- a/src/plugins/platforms/wasm/qwasmdrag.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only - -#include "qwasmdrag.h" - -#include "qwasmdom.h" -#include "qwasmeventtranslator.h" -#include <qpa/qwindowsysteminterface.h> -#include <QMimeData> - -#include <emscripten.h> -#include <emscripten/val.h> -#include <emscripten/bind.h> - -#include <memory> -#include <string> - -QT_BEGIN_NAMESPACE - -namespace { -Qt::DropAction parseDropActions(emscripten::val event) -{ - const std::string dEffect = event["dataTransfer"]["dropEffect"].as<std::string>(); - - if (dEffect == "copy") - return Qt::CopyAction; - else if (dEffect == "move") - return Qt::MoveAction; - else if (dEffect == "link") - return Qt::LinkAction; - return Qt::IgnoreAction; -} -} // namespace - -void dropEvent(emscripten::val event) -{ - // someone dropped a file into the browser window - // event is dataTransfer object - // if drop event from outside browser, we do not get any mouse release, maybe mouse move - // after the drop event - event.call<void>("preventDefault"); // prevent browser from handling drop event - - static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr; - readDataCancellation = qstdweb::readDataTransfer( - event["dataTransfer"], - [](QByteArray fileContent) { - QImage image; - image.loadFromData(fileContent, nullptr); - return image; - }, - [wasmScreen = reinterpret_cast<QWasmScreen *>( - event["target"]["data-qtdropcontext"].as<quintptr>()), - event](std::unique_ptr<QMimeData> data) { - const auto mouseDropPoint = QPoint(event["x"].as<int>(), event["y"].as<int>()); - const auto button = MouseEvent::buttonFromWeb(event["button"].as<int>()); - const Qt::KeyboardModifiers modifiers = KeyboardModifier::getForEvent(event); - const auto dropAction = parseDropActions(event); - auto *window = wasmScreen->topLevelAt(mouseDropPoint); - - QWindowSystemInterface::handleDrag(window, data.get(), mouseDropPoint, dropAction, - button, modifiers); - - // drag drop - QWindowSystemInterface::handleDrop(window, data.get(), mouseDropPoint, dropAction, - button, modifiers); - - // drag leave - QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, {}, - {}); - }); -} - -EMSCRIPTEN_BINDINGS(drop_module) -{ - function("qtDrop", &dropEvent); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmdrag.h b/src/plugins/platforms/wasm/qwasmdrag.h deleted file mode 100644 index 624e9e3db6..0000000000 --- a/src/plugins/platforms/wasm/qwasmdrag.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only - -#ifndef QWASMDRAG_H -#define QWASMDRAG_H - -#include <QtCore/qtconfigmacros.h> - -#include <emscripten/val.h> - -QT_BEGIN_NAMESPACE - -void dropEvent(emscripten::val event); - -QT_END_NAMESPACE - -#endif // QWASMDRAG_H diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp index 19730c2c68..b6568e13fa 100644 --- a/src/plugins/platforms/wasm/qwasmevent.cpp +++ b/src/plugins/platforms/wasm/qwasmevent.cpp @@ -16,10 +16,63 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>( } } // namespace KeyboardModifier -std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event) +Event::Event(EventType type, emscripten::val target) : type(type), target(target) { } + +Event::~Event() = default; + +Event::Event(const Event &other) = default; + +Event::Event(Event &&other) = default; + +Event &Event::operator=(const Event &other) = default; + +Event &Event::operator=(Event &&other) = default; + +MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event["target"]) +{ + mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>()); + mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>()); + // The current button state (event.buttons) may be out of sync for some PointerDown + // events where the "down" state is very brief, for example taps on Apple trackpads. + // Qt expects that the current button state is in sync with the event, so we sync + // it up here. + if (type == EventType::PointerDown) + mouseButtons |= mouseButton; + localPoint = QPoint(event["offsetX"].as<int>(), event["offsetY"].as<int>()); + pointInPage = QPoint(event["pageX"].as<int>(), event["pageY"].as<int>()); + pointInViewport = QPoint(event["clientX"].as<int>(), event["clientY"].as<int>()); + modifiers = KeyboardModifier::getForEvent(event); +} + +MouseEvent::~MouseEvent() = default; + +MouseEvent::MouseEvent(const MouseEvent &other) = default; + +MouseEvent::MouseEvent(MouseEvent &&other) = default; + +MouseEvent &MouseEvent::operator=(const MouseEvent &other) = default; + +MouseEvent &MouseEvent::operator=(MouseEvent &&other) = default; + +PointerEvent::PointerEvent(EventType type, emscripten::val event) : MouseEvent(type, event) { - PointerEvent ret; + pointerId = event["pointerId"].as<int>(); + pointerType = event["pointerType"].as<std::string>() == "mouse" ? PointerType::Mouse + : PointerType::Other; +} + +PointerEvent::~PointerEvent() = default; + +PointerEvent::PointerEvent(const PointerEvent &other) = default; + +PointerEvent::PointerEvent(PointerEvent &&other) = default; + +PointerEvent &PointerEvent::operator=(const PointerEvent &other) = default; +PointerEvent &PointerEvent::operator=(PointerEvent &&other) = default; + +std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event) +{ const auto eventType = ([&event]() -> std::optional<EventType> { const auto eventTypeString = event["type"].as<std::string>(); @@ -38,27 +91,47 @@ std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event) if (!eventType) return std::nullopt; - ret.type = *eventType; - ret.target = event["target"]; - ret.pointerType = event["pointerType"].as<std::string>() == "mouse" ? - PointerType::Mouse : PointerType::Other; - ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>()); - ret.mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>()); + return PointerEvent(*eventType, event); +} - // The current button state (event.buttons) may be out of sync for some PointerDown - // events where the "down" state is very brief, for example taps on Apple trackpads. - // Qt expects that the current button state is in sync with the event, so we sync - // it up here. - if (*eventType == EventType::PointerDown) - ret.mouseButtons |= ret.mouseButton; +DragEvent::DragEvent(EventType type, emscripten::val event) + : MouseEvent(type, event), dataTransfer(event["dataTransfer"]) +{ + dropAction = ([event]() { + const std::string effect = event["dataTransfer"]["dropEffect"].as<std::string>(); + + if (effect == "copy") + return Qt::CopyAction; + else if (effect == "move") + return Qt::MoveAction; + else if (effect == "link") + return Qt::LinkAction; + return Qt::IgnoreAction; + })(); +} - ret.localPoint = QPoint(event["offsetX"].as<int>(), event["offsetY"].as<int>()); - ret.pointInPage = QPoint(event["pageX"].as<int>(), event["pageY"].as<int>()); - ret.pointInViewport = QPoint(event["clientX"].as<int>(), event["clientY"].as<int>()); - ret.pointerId = event["pointerId"].as<int>(); - ret.modifiers = KeyboardModifier::getForEvent(event); +DragEvent::~DragEvent() = default; - return ret; +DragEvent::DragEvent(const DragEvent &other) = default; + +DragEvent::DragEvent(DragEvent &&other) = default; + +DragEvent &DragEvent::operator=(const DragEvent &other) = default; + +DragEvent &DragEvent::operator=(DragEvent &&other) = default; + +std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event) +{ + const auto eventType = ([&event]() -> std::optional<EventType> { + const auto eventTypeString = event["type"].as<std::string>(); + + if (eventTypeString == "drop") + return EventType::Drop; + return std::nullopt; + })(); + if (!eventType) + return std::nullopt; + return DragEvent(*eventType, event); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h index f9d6411d60..215d06bae5 100644 --- a/src/plugins/platforms/wasm/qwasmevent.h +++ b/src/plugins/platforms/wasm/qwasmevent.h @@ -18,6 +18,7 @@ QT_BEGIN_NAMESPACE enum class EventType { + Drop, PointerDown, PointerMove, PointerUp, @@ -107,13 +108,20 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>( } // namespace KeyboardModifier -struct Q_CORE_EXPORT Event +struct Event { EventType type; emscripten::val target = emscripten::val::undefined(); + + Event(EventType type, emscripten::val target); + ~Event(); + Event(const Event &other); + Event(Event &&other); + Event &operator=(const Event &other); + Event &operator=(Event &&other); }; -struct Q_CORE_EXPORT MouseEvent : public Event +struct MouseEvent : public Event { QPoint localPoint; QPoint pointInPage; @@ -122,6 +130,13 @@ struct Q_CORE_EXPORT MouseEvent : public Event Qt::MouseButtons mouseButtons; QFlags<Qt::KeyboardModifier> modifiers; + MouseEvent(EventType type, emscripten::val webEvent); + ~MouseEvent(); + MouseEvent(const MouseEvent &other); + MouseEvent(MouseEvent &&other); + MouseEvent &operator=(const MouseEvent &other); + MouseEvent &operator=(MouseEvent &&other); + static constexpr Qt::MouseButton buttonFromWeb(int webButton) { switch (webButton) { case 0: @@ -158,14 +173,36 @@ struct Q_CORE_EXPORT MouseEvent : public Event } }; -struct Q_CORE_EXPORT PointerEvent : public MouseEvent +struct PointerEvent : public MouseEvent { static std::optional<PointerEvent> fromWeb(emscripten::val webEvent); + PointerEvent(EventType type, emscripten::val webEvent); + ~PointerEvent(); + PointerEvent(const PointerEvent &other); + PointerEvent(PointerEvent &&other); + PointerEvent &operator=(const PointerEvent &other); + PointerEvent &operator=(PointerEvent &&other); + PointerType pointerType; int pointerId; }; +struct DragEvent : public MouseEvent +{ + static std::optional<DragEvent> fromWeb(emscripten::val webEvent); + + DragEvent(EventType type, emscripten::val webEvent); + ~DragEvent(); + DragEvent(const DragEvent &other); + DragEvent(DragEvent &&other); + DragEvent &operator=(const DragEvent &other); + DragEvent &operator=(DragEvent &&other); + + Qt::DropAction dropAction; + emscripten::val dataTransfer; +}; + QT_END_NAMESPACE #endif // QWASMEVENT_H diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 090218a118..b92e456668 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -80,12 +80,6 @@ QWasmIntegration::QWasmIntegration() m_clipboard(new QWasmClipboard), m_accessibility(new QWasmAccessibility) { - // Temporary measure to make dropEvent appear in the library. EMSCRIPTEN_KEEPALIVE does not - // work, nor does a Q_CONSTRUCTOR_FUNCTION in qwasmdrag.cpp. - volatile bool foolEmcc = false; - if (foolEmcc) - dropEvent(emscripten::val::undefined()); - s_instance = this; touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>(); diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 8468c4c9e1..decf25009e 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -12,10 +12,6 @@ #include <qpa/qplatformscreen.h> #include <qpa/qplatforminputcontext.h> -#if QT_CONFIG(draganddrop) -# include "qwasmdrag.h" -#endif - #include <QtCore/qhash.h> #include <private/qsimpledrag_p.h> diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index a8f577cfea..3735c7dff4 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -84,6 +84,12 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerenter", callback); m_pointerLeaveCallback = std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", callback); + + m_dropCallback = std::make_unique<qstdweb::EventCallback>( + m_qtWindow, "drop", [this](emscripten::val event) { + if (processDrop(*DragEvent::fromWeb(event))) + event.call<void>("preventDefault"); + }); } QWasmWindow::~QWasmWindow() @@ -418,6 +424,30 @@ bool QWasmWindow::processPointer(const PointerEvent &event) return false; } +bool QWasmWindow::processDrop(const DragEvent &event) +{ + m_dropDataReadCancellationFlag = qstdweb::readDataTransfer( + event.dataTransfer, + [](QByteArray fileContent) { + QImage image; + image.loadFromData(fileContent, nullptr); + return image; + }, + [this, event](std::unique_ptr<QMimeData> data) { + QWindowSystemInterface::handleDrag(window(), data.get(), event.pointInPage, + event.dropAction, event.mouseButton, + event.modifiers); + + QWindowSystemInterface::handleDrop(window(), data.get(), event.pointInPage, + event.dropAction, event.mouseButton, + event.modifiers); + + QWindowSystemInterface::handleDrag(window(), nullptr, QPoint(), Qt::IgnoreAction, + {}, {}); + }); + return true; +} + QRect QWasmWindow::normalGeometry() const { return m_normalGeometry; diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index 5651495c74..906a7a1daf 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -18,13 +18,21 @@ #include <emscripten/val.h> +#include <memory> + QT_BEGIN_NAMESPACE namespace qstdweb { +struct CancellationFlag; +} + +namespace qstdweb { class EventCallback; } class ClientArea; +struct DragEvent; +struct PointerEvent; class QWasmWindow final : public QPlatformWindow { @@ -84,6 +92,7 @@ private: void applyWindowState(); bool processPointer(const PointerEvent &event); + bool processDrop(const DragEvent &event); QWindow *m_window = nullptr; QWasmCompositor *m_compositor = nullptr; @@ -105,6 +114,8 @@ private: std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback; std::unique_ptr<qstdweb::EventCallback> m_pointerMoveCallback; + std::unique_ptr<qstdweb::EventCallback> m_dropCallback; + Qt::WindowStates m_state = Qt::WindowNoState; Qt::WindowStates m_previousWindowState = Qt::WindowNoState; @@ -120,6 +131,8 @@ private: friend class QWasmCompositor; friend class QWasmEventTranslator; bool windowIsPopupType(Qt::WindowFlags flags) const; + + std::shared_ptr<qstdweb::CancellationFlag> m_dropDataReadCancellationFlag; }; QT_END_NAMESPACE |