Streamline reading of js DataTransfer object

qwasmclipboard.cpp and qwasmdrag.cpp had the same logic that read
the js DataTransfer object implemented twice with small differences.
Use a single implementation in both.

This also introduces a clearer memory ownership model in the reader
code, and fixes a potential race condition by introducing a cancellation
flag.

Removed the useless QWasmDrag type which was in essence a SimpleDrag
and made the m_drag in QWasmIntegration a smart pointer.

Fixes: QTBUG-109626
Change-Id: I5b76dd3b70ab2e5a8364d9a136c970ee8d4fae9c
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
(cherry picked from commit 16bf899557febb8c0762e64ce88acf21bc84e334)
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io>
This commit is contained in:
Mikolaj Boc 2022-12-19 17:22:11 +01:00
parent 4ab04b35ab
commit 00bb651919
9 changed files with 229 additions and 309 deletions

View File

@ -5,6 +5,8 @@
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtCore/qfile.h> #include <QtCore/qfile.h>
#include <QtCore/qmimedata.h>
#include <emscripten/bind.h> #include <emscripten/bind.h>
#include <emscripten/emscripten.h> #include <emscripten/emscripten.h>
#include <emscripten/html5.h> #include <emscripten/html5.h>
@ -368,6 +370,111 @@ bool jsHaveAsyncify() { return false; }
#endif #endif
struct DataTransferReader
{
public:
using DoneCallback = std::function<void(std::unique_ptr<QMimeData>)>;
static std::shared_ptr<CancellationFlag> read(emscripten::val webDataTransfer,
std::function<QVariant(QByteArray)> imageReader,
DoneCallback onCompleted)
{
auto cancellationFlag = std::make_shared<CancellationFlag>();
(new DataTransferReader(std::move(onCompleted), std::move(imageReader), cancellationFlag))
->read(webDataTransfer);
return cancellationFlag;
}
~DataTransferReader() = default;
private:
DataTransferReader(DoneCallback onCompleted, std::function<QVariant(QByteArray)> imageReader,
std::shared_ptr<CancellationFlag> cancellationFlag)
: mimeData(std::make_unique<QMimeData>()),
imageReader(std::move(imageReader)),
onCompleted(std::move(onCompleted)),
cancellationFlag(cancellationFlag)
{
}
void read(emscripten::val webDataTransfer)
{
enum class ItemKind {
File,
String,
};
const auto items = webDataTransfer["items"];
for (int i = 0; i < items["length"].as<int>(); ++i) {
const auto item = items[i];
const auto itemKind =
item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
switch (itemKind) {
case ItemKind::File: {
++fileCount;
qstdweb::File file(item.call<emscripten::val>("getAsFile"));
QByteArray fileContent(file.size(), Qt::Uninitialized);
file.stream(fileContent.data(), [this, itemMimeType, fileContent]() {
if (!fileContent.isEmpty()) {
if (itemMimeType.startsWith("image/")) {
mimeData->setImageData(imageReader(fileContent));
} else {
mimeData->setData(itemMimeType, fileContent.data());
}
}
++doneCount;
onFileRead();
});
break;
}
case ItemKind::String:
if (itemMimeType.contains("STRING", Qt::CaseSensitive)
|| itemMimeType.contains("TEXT", Qt::CaseSensitive)) {
break;
}
QString a;
const QString data = QString::fromStdString(webDataTransfer.call<std::string>(
"getData", emscripten::val(itemMimeType.toStdString())));
if (!data.isEmpty()) {
if (itemMimeType == "text/html")
mimeData->setHtml(data);
else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
mimeData->setText(data); // the type can be empty
else
mimeData->setData(itemMimeType, data.toLocal8Bit());
}
break;
}
}
onFileRead();
}
void onFileRead()
{
Q_ASSERT(doneCount <= fileCount);
if (doneCount < fileCount)
return;
std::unique_ptr<DataTransferReader> deleteThisLater(this);
if (!cancellationFlag.expired())
onCompleted(std::move(mimeData));
}
int fileCount = 0;
int doneCount = 0;
std::unique_ptr<QMimeData> mimeData;
std::function<QVariant(QByteArray)> imageReader;
DoneCallback onCompleted;
std::weak_ptr<CancellationFlag> cancellationFlag;
};
} // namespace } // namespace
ArrayBuffer::ArrayBuffer(uint32_t size) ArrayBuffer::ArrayBuffer(uint32_t size)
@ -738,6 +845,13 @@ bool haveAsyncify()
return HaveAsyncify; return HaveAsyncify;
} }
std::shared_ptr<CancellationFlag>
readDataTransfer(emscripten::val webDataTransfer, std::function<QVariant(QByteArray)> imageReader,
std::function<void(std::unique_ptr<QMimeData>)> onDone)
{
return DataTransferReader::read(webDataTransfer, std::move(imageReader), std::move(onDone));
}
} // namespace qstdweb } // namespace qstdweb
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -16,15 +16,22 @@
// //
#include <private/qglobal_p.h> #include <private/qglobal_p.h>
#include <emscripten/val.h>
#include <cstdint>
#include <functional>
#include "initializer_list"
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include "QtCore/qhash.h" #include "QtCore/qhash.h"
#include <emscripten/val.h>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <utility>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMimeData;
namespace qstdweb { namespace qstdweb {
extern const char makeContextfulPromiseFunctionName[]; extern const char makeContextfulPromiseFunctionName[];
@ -195,6 +202,14 @@ namespace qstdweb {
} }
bool haveAsyncify(); bool haveAsyncify();
struct CancellationFlag
{
};
std::shared_ptr<CancellationFlag>
readDataTransfer(emscripten::val webObject, std::function<QVariant(QByteArray)> imageReader,
std::function<void(std::unique_ptr<QMimeData>)> onDone);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -2,20 +2,18 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmclipboard.h" #include "qwasmclipboard.h"
#include "qwasmdom.h"
#include "qwasmwindow.h" #include "qwasmwindow.h"
#include "qwasmstring.h" #include "qwasmstring.h"
#include <private/qstdweb_p.h> #include <private/qstdweb_p.h>
#include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
#include <QBuffer> #include <QBuffer>
#include <QString> #include <QString>
#include <emscripten/val.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
using namespace emscripten; using namespace emscripten;
@ -68,93 +66,29 @@ static void qClipboardCopyTo(val event)
commonCopyEvent(event); commonCopyEvent(event);
} }
static void qWasmClipboardPaste(QMimeData *mData) static void qClipboardPasteTo(val event)
{ {
// Persist clipboard data so that the app can read it when handling the CTRL+V event.call<void>("preventDefault"); // prevent browser from handling drop event
QWasmIntegration::get()->clipboard()->
QPlatformClipboard::setMimeData(mData, QClipboard::Clipboard);
QWindowSystemInterface::handleKeyEvent( static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr;
0, QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier, "V"); readDataCancellation = qstdweb::readDataTransfer(
} event["clipboardData"],
[](QByteArray fileContent) {
QImage image;
image.loadFromData(fileContent, nullptr);
return image;
},
[event](std::unique_ptr<QMimeData> data) {
if (data->formats().isEmpty())
return;
static void qClipboardPasteTo(val dataTransfer) // Persist clipboard data so that the app can read it when handling the CTRL+V
{ QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(
enum class ItemKind { data.release(), QClipboard::Clipboard);
File,
String,
};
struct Data QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
{ Qt::ControlModifier, "V");
std::unique_ptr<QMimeData> data; });
int fileCount = 0;
int doneCount = 0;
};
auto sharedData = std::make_shared<Data>();
sharedData->data = std::make_unique<QMimeData>();
auto continuation = [sharedData]() {
Q_ASSERT(sharedData->doneCount <= sharedData->fileCount);
if (sharedData->doneCount < sharedData->fileCount)
return;
if (!sharedData->data->formats().isEmpty())
qWasmClipboardPaste(sharedData->data.release());
};
const val clipboardData = dataTransfer["clipboardData"];
const val items = clipboardData["items"];
for (int i = 0; i < items["length"].as<int>(); ++i) {
const val item = items[i];
const auto itemKind =
item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
switch (itemKind) {
case ItemKind::File: {
++sharedData->fileCount;
qstdweb::File file(item.call<emscripten::val>("getAsFile"));
QByteArray fileContent(file.size(), Qt::Uninitialized);
file.stream(fileContent.data(),
[continuation, itemMimeType, fileContent, sharedData]() {
if (!fileContent.isEmpty()) {
if (itemMimeType.startsWith("image/")) {
QImage image;
image.loadFromData(fileContent, nullptr);
sharedData->data->setImageData(image);
} else {
sharedData->data->setData(itemMimeType, fileContent.data());
}
}
++sharedData->doneCount;
continuation();
});
break;
}
case ItemKind::String:
if (itemMimeType.contains("STRING", Qt::CaseSensitive)
|| itemMimeType.contains("TEXT", Qt::CaseSensitive)) {
break;
}
const QString data = QWasmString::toQString(
clipboardData.call<val>("getData", val(itemMimeType.toStdString())));
if (!data.isEmpty()) {
if (itemMimeType == "text/html")
sharedData->data->setHtml(data);
else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
sharedData->data->setText(data); // the type can be empty
else
sharedData->data->setData(itemMimeType, data.toLocal8Bit());
}
break;
}
}
continuation();
} }
EMSCRIPTEN_BINDINGS(qtClipboardModule) { EMSCRIPTEN_BINDINGS(qtClipboardModule) {

View File

@ -3,14 +3,18 @@
#include "qwasmdom.h" #include "qwasmdom.h"
#include <QMimeData>
#include <QtCore/qpoint.h> #include <QtCore/qpoint.h>
#include <QtCore/qrect.h> #include <QtCore/qrect.h>
#include <QtGui/qimage.h>
#include <private/qstdweb_p.h>
#include <utility> #include <utility>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace dom { namespace dom {
void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag) void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag)
{ {
if (flag) { if (flag) {
@ -31,6 +35,7 @@ QPoint mapPoint(emscripten::val source, emscripten::val target, const QPoint &po
auto offset = sourceBoundingRect.topLeft() - targetBoundingRect.topLeft(); auto offset = sourceBoundingRect.topLeft() - targetBoundingRect.topLeft();
return (point + offset).toPoint(); return (point + offset).toPoint();
} }
} // namespace dom } // namespace dom
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -8,6 +8,8 @@
#include <emscripten/val.h> #include <emscripten/val.h>
#include <functional>
#include <memory>
#include <string> #include <string>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE

View File

@ -3,207 +3,76 @@
#include "qwasmdrag.h" #include "qwasmdrag.h"
#include <iostream> #include "qwasmdom.h"
#include <QMimeDatabase> #include "qwasmeventtranslator.h"
#include <qpa/qwindowsysteminterface.h>
#include <QMimeData>
#include <emscripten.h> #include <emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/val.h> #include <emscripten/val.h>
#include <emscripten/bind.h> #include <emscripten/bind.h>
#include <private/qstdweb_p.h>
#include <qpa/qwindowsysteminterface.h> #include <memory>
#include <private/qsimpledrag_p.h> #include <string>
#include "qwasmcompositor.h"
#include "qwasmeventtranslator.h"
#include <QtCore/QEventLoop>
#include <QMimeData>
#include <private/qshapedpixmapdndwindow_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
using namespace emscripten; namespace {
Qt::DropAction parseDropActions(emscripten::val event)
static void getTextPlainCallback(val m_string)
{ {
QWasmDrag *thisDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag()); const std::string dEffect = event["dataTransfer"]["dropEffect"].as<std::string>();
thisDrag->m_mimeData->setText(QString::fromStdString(m_string.as<std::string>()));
thisDrag->qWasmDrop(); if (dEffect == "copy")
return Qt::CopyAction;
else if (dEffect == "move")
return Qt::MoveAction;
else if (dEffect == "link")
return Qt::LinkAction;
return Qt::IgnoreAction;
} }
} // namespace
static void getTextUrlCallback(val m_string) void dropEvent(emscripten::val event)
{
QWasmDrag *thisDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag());
thisDrag->m_mimeData->setData(QStringLiteral("text/uri-list"),
QByteArray::fromStdString(m_string.as<std::string>()));
thisDrag->qWasmDrop();
}
static void getTextHtmlCallback(val m_string)
{
QWasmDrag *thisDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag());
thisDrag->m_mimeData->setHtml(QString::fromStdString(m_string.as<std::string>()));
thisDrag->qWasmDrop();
}
static void dropEvent(val event)
{ {
// someone dropped a file into the browser window // someone dropped a file into the browser window
// event is dataTransfer object // event is dataTransfer object
// if drop event from outside browser, we do not get any mouse release, maybe mouse move // if drop event from outside browser, we do not get any mouse release, maybe mouse move
// after the drop event // after the drop event
// data-context thing was not working here :(
QWasmDrag *wasmDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag());
wasmDrag->m_wasmScreen =
reinterpret_cast<QWasmScreen*>(event["target"]["data-qtdropcontext"].as<quintptr>());
wasmDrag->m_mouseDropPoint = QPoint(event["x"].as<int>(), event["y"].as<int>());
if (wasmDrag->m_mimeData)
delete wasmDrag->m_mimeData;
wasmDrag->m_mimeData = new QMimeData;
wasmDrag->m_qButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
wasmDrag->m_keyModifiers = Qt::NoModifier;
if (event["altKey"].as<bool>())
wasmDrag->m_keyModifiers |= Qt::AltModifier;
if (event["ctrlKey"].as<bool>())
wasmDrag->m_keyModifiers |= Qt::ControlModifier;
if (event["metaKey"].as<bool>())
wasmDrag->m_keyModifiers |= Qt::MetaModifier;
event.call<void>("preventDefault"); // prevent browser from handling drop event event.call<void>("preventDefault"); // prevent browser from handling drop event
std::string dEffect = event["dataTransfer"]["dropEffect"].as<std::string>(); 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["currentTarget"]["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);
wasmDrag->m_dropActions = Qt::IgnoreAction; QWindowSystemInterface::handleDrag(window, data.get(), mouseDropPoint, dropAction,
if (dEffect == "copy") button, modifiers);
wasmDrag->m_dropActions = Qt::CopyAction;
if (dEffect == "move")
wasmDrag->m_dropActions = Qt::MoveAction;
if (dEffect == "link")
wasmDrag->m_dropActions = Qt::LinkAction;
val dt = event["dataTransfer"]["items"]["length"]; // drag drop
QWindowSystemInterface::handleDrop(window, data.get(), mouseDropPoint, dropAction,
button, modifiers);
val typesCount = event["dataTransfer"]["types"]["length"]; // drag leave
QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, {},
// handle mimedata {});
int count = dt.as<int>();
wasmDrag->m_mimeTypesCount = count;
// kind is file type: file or string
for (int i=0; i < count; i++) {
val item = event["dataTransfer"]["items"][i];
val kind = item["kind"];
val fileType = item["type"];
if (kind.as<std::string>() == "file") {
val m_file = item.call<val>("getAsFile");
if (m_file.isUndefined()) {
continue;
}
qstdweb::File file(m_file);
QString mimeFormat = QString::fromStdString(file.type());
QByteArray fileContent;
fileContent.resize(file.size());
file.stream(fileContent.data(), [mimeFormat, fileContent]() {
if (!fileContent.isEmpty()) {
QWasmDrag *wasmDrag = static_cast<QWasmDrag *>(QWasmIntegration::get()->drag());
if (mimeFormat.contains("image")) {
QImage image;
image.loadFromData(fileContent, nullptr);
wasmDrag->m_mimeData->setImageData(image);
} else {
wasmDrag->m_mimeData->setData(mimeFormat, fileContent.data());
}
wasmDrag->qWasmDrop();
}
}); });
} else { // string
if (fileType.as<std::string>() == "text/uri-list"
|| fileType.as<std::string>() == "text/x-moz-url") {
item.call<val>("getAsString", val::module_property("qtgetTextUrl"));
} else if (fileType.as<std::string>() == "text/html") {
item.call<val>("getAsString", val::module_property("qtgetTextHtml"));
} else { // handle everything else here as plain text
item.call<val>("getAsString", val::module_property("qtgetTextPlain"));
}
}
}
} }
EMSCRIPTEN_BINDINGS(drop_module) { EMSCRIPTEN_BINDINGS(drop_module)
{
function("qtDrop", &dropEvent); function("qtDrop", &dropEvent);
function("qtgetTextPlain", &getTextPlainCallback);
function("qtgetTextUrl", &getTextUrlCallback);
function("qtgetTextHtml", &getTextHtmlCallback);
}
QWasmDrag::QWasmDrag()
{
init();
}
QWasmDrag::~QWasmDrag()
{
if (m_mimeData)
delete m_mimeData;
}
void QWasmDrag::init()
{
}
void QWasmDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
QSimpleDrag::drop(globalPos, b, mods);
}
void QWasmDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
QSimpleDrag::move(globalPos, b, mods);
}
void QWasmDrag::qWasmDrop()
{
// collect mime
QWasmDrag *thisDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag());
if (thisDrag->m_mimeTypesCount != thisDrag->m_mimeData->formats().size())
return; // keep collecting mimetypes
// start drag enter
QWindowSystemInterface::handleDrag(thisDrag->m_wasmScreen->topLevelAt(thisDrag->m_mouseDropPoint),
thisDrag->m_mimeData,
thisDrag->m_mouseDropPoint,
thisDrag->m_dropActions,
thisDrag->m_qButton,
thisDrag->m_keyModifiers);
// drag drop
QWindowSystemInterface::handleDrop(thisDrag->m_wasmScreen->topLevelAt(thisDrag->m_mouseDropPoint),
thisDrag->m_mimeData,
thisDrag->m_mouseDropPoint,
thisDrag->m_dropActions,
thisDrag->m_qButton,
thisDrag->m_keyModifiers);
// drag leave
QWindowSystemInterface::handleDrag(thisDrag->m_wasmScreen->topLevelAt(thisDrag->m_mouseDropPoint),
nullptr,
QPoint(),
Qt::IgnoreAction, { }, { });
thisDrag->m_mimeData->clear();
thisDrag->m_mimeTypesCount = 0;
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -4,39 +4,13 @@
#ifndef QWASMDRAG_H #ifndef QWASMDRAG_H
#define QWASMDRAG_H #define QWASMDRAG_H
#include <qpa/qplatformdrag.h> #include <QtCore/qtconfigmacros.h>
#include <private/qsimpledrag_p.h>
#include <private/qstdweb_p.h>
#include <QDrag>
#include "qwasmscreen.h"
QT_REQUIRE_CONFIG(draganddrop); #include <emscripten/val.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QWasmDrag : public QSimpleDrag void dropEvent(emscripten::val event);
{
public:
QWasmDrag();
~QWasmDrag();
void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
Qt::MouseButton m_qButton;
QPoint m_mouseDropPoint;
QFlags<Qt::KeyboardModifier> m_keyModifiers;
Qt::DropActions m_dropActions;
QWasmScreen *m_wasmScreen = nullptr;
int m_mimeTypesCount = 0;
QMimeData *m_mimeData = nullptr;
void qWasmDrop();
private:
void init();
};
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -81,6 +81,12 @@ QWasmIntegration::QWasmIntegration()
m_clipboard(new QWasmClipboard), m_clipboard(new QWasmClipboard),
m_accessibility(new QWasmAccessibility) 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; s_instance = this;
touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>(); touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>();
@ -122,7 +128,7 @@ QWasmIntegration::QWasmIntegration()
visualViewport.call<void>("addEventListener", val("resize"), visualViewport.call<void>("addEventListener", val("resize"),
val::module_property("qtResizeAllScreens")); val::module_property("qtResizeAllScreens"));
} }
m_drag = new QWasmDrag(); m_drag = std::make_unique<QSimpleDrag>();
} }
QWasmIntegration::~QWasmIntegration() QWasmIntegration::~QWasmIntegration()
@ -139,7 +145,6 @@ QWasmIntegration::~QWasmIntegration()
delete m_desktopServices; delete m_desktopServices;
if (m_platformInputContext) if (m_platformInputContext)
delete m_platformInputContext; delete m_platformInputContext;
delete m_drag;
delete m_accessibility; delete m_accessibility;
for (const auto &elementAndScreen : m_screens) for (const auto &elementAndScreen : m_screens)
@ -328,7 +333,7 @@ quint64 QWasmIntegration::getTimestamp()
#if QT_CONFIG(draganddrop) #if QT_CONFIG(draganddrop)
QPlatformDrag *QWasmIntegration::drag() const QPlatformDrag *QWasmIntegration::drag() const
{ {
return m_drag; return m_drag.get();
} }
#endif // QT_CONFIG(draganddrop) #endif // QT_CONFIG(draganddrop)

View File

@ -6,23 +6,25 @@
#include "qwasmwindow.h" #include "qwasmwindow.h"
#include "qwasminputcontext.h"
#include <qpa/qplatformintegration.h> #include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h> #include <qpa/qplatformscreen.h>
#include <qpa/qplatforminputcontext.h> #include <qpa/qplatforminputcontext.h>
#if QT_CONFIG(draganddrop)
# include "qwasmdrag.h"
#endif
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
#include <private/qsimpledrag_p.h>
#include <private/qstdweb_p.h>
#include <emscripten.h> #include <emscripten.h>
#include <emscripten/html5.h> #include <emscripten/html5.h>
#include <emscripten/val.h> #include <emscripten/val.h>
#include "qwasminputcontext.h"
#include <private/qstdweb_p.h>
#if QT_CONFIG(draganddrop)
#include "qwasmdrag.h"
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QWasmEventTranslator; class QWasmEventTranslator;
@ -97,7 +99,7 @@ private:
mutable QWasmInputContext *m_platformInputContext = nullptr; mutable QWasmInputContext *m_platformInputContext = nullptr;
#if QT_CONFIG(draganddrop) #if QT_CONFIG(draganddrop)
QWasmDrag *m_drag; std::unique_ptr<QSimpleDrag> m_drag;
#endif #endif
}; };