summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorMikolaj Boc <mikolaj.boc@qt.io>2023-01-20 15:12:38 +0100
committerMikolaj Boc <mikolaj.boc@qt.io>2023-01-20 18:00:26 +0100
commit9b64bf0874b9e9323d6eadad2a8023c888f25182 (patch)
tree89bfd88836f6ba61c653dbe083612c1fb3ae636f /src/plugins/platforms
parentc290e742c6e780f0b507ea0f3ba287f2f6045572 (diff)
Handle the drop event in the wasm window element
Drop events are now handled in the wasm window element, which allows the browser to select the drop target automatically. This also fixes the case where drop data transfer finishes reading when a window has already been closed and destroyed - the cancellation flag is now owned by window so it gets invalidated as soon as window is gone. The code has also been structured with a new DragEvent passthrough. Fixes: QTBUG-109581 Change-Id: Ie3eb7446e2181fd540517f39397e8b35f111d009 Reviewed-by: MikoĊ‚aj Boc <Mikolaj.Boc@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp8
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.cpp78
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.h17
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.cpp113
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.h43
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp6
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h4
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp30
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.h13
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