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:
parent
4ab04b35ab
commit
00bb651919
@ -5,6 +5,8 @@
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfile.h>
|
||||
#include <QtCore/qmimedata.h>
|
||||
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
@ -368,6 +370,111 @@ bool jsHaveAsyncify() { return false; }
|
||||
|
||||
#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
|
||||
|
||||
ArrayBuffer::ArrayBuffer(uint32_t size)
|
||||
@ -738,6 +845,13 @@ bool 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
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -16,15 +16,22 @@
|
||||
//
|
||||
|
||||
#include <private/qglobal_p.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include "initializer_list"
|
||||
#include <QtCore/qglobal.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
|
||||
|
||||
class QMimeData;
|
||||
|
||||
namespace qstdweb {
|
||||
extern const char makeContextfulPromiseFunctionName[];
|
||||
|
||||
@ -195,6 +202,14 @@ namespace qstdweb {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -2,20 +2,18 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include "qwasmclipboard.h"
|
||||
#include "qwasmdom.h"
|
||||
#include "qwasmwindow.h"
|
||||
#include "qwasmstring.h"
|
||||
#include <private/qstdweb_p.h>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QBuffer>
|
||||
#include <QString>
|
||||
|
||||
#include <emscripten/val.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
using namespace emscripten;
|
||||
|
||||
@ -68,93 +66,29 @@ static void qClipboardCopyTo(val 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
|
||||
QWasmIntegration::get()->clipboard()->
|
||||
QPlatformClipboard::setMimeData(mData, QClipboard::Clipboard);
|
||||
event.call<void>("preventDefault"); // prevent browser from handling drop event
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(
|
||||
0, QEvent::KeyPress, Qt::Key_V, Qt::ControlModifier, "V");
|
||||
}
|
||||
|
||||
static void qClipboardPasteTo(val dataTransfer)
|
||||
{
|
||||
enum class ItemKind {
|
||||
File,
|
||||
String,
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
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/")) {
|
||||
static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr;
|
||||
readDataCancellation = qstdweb::readDataTransfer(
|
||||
event["clipboardData"],
|
||||
[](QByteArray fileContent) {
|
||||
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())));
|
||||
return image;
|
||||
},
|
||||
[event](std::unique_ptr<QMimeData> data) {
|
||||
if (data->formats().isEmpty())
|
||||
return;
|
||||
|
||||
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();
|
||||
// Persist clipboard data so that the app can read it when handling the CTRL+V
|
||||
QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(
|
||||
data.release(), QClipboard::Clipboard);
|
||||
|
||||
QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
|
||||
Qt::ControlModifier, "V");
|
||||
});
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
|
||||
|
@ -3,14 +3,18 @@
|
||||
|
||||
#include "qwasmdom.h"
|
||||
|
||||
#include <QMimeData>
|
||||
#include <QtCore/qpoint.h>
|
||||
#include <QtCore/qrect.h>
|
||||
#include <QtGui/qimage.h>
|
||||
#include <private/qstdweb_p.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace dom {
|
||||
|
||||
void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag)
|
||||
{
|
||||
if (flag) {
|
||||
@ -31,6 +35,7 @@ QPoint mapPoint(emscripten::val source, emscripten::val target, const QPoint &po
|
||||
auto offset = sourceBoundingRect.topLeft() - targetBoundingRect.topLeft();
|
||||
return (point + offset).toPoint();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
@ -3,207 +3,76 @@
|
||||
|
||||
#include "qwasmdrag.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <QMimeDatabase>
|
||||
#include "qwasmdom.h"
|
||||
#include "qwasmeventtranslator.h"
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QMimeData>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <private/qstdweb_p.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <private/qsimpledrag_p.h>
|
||||
#include "qwasmcompositor.h"
|
||||
#include "qwasmeventtranslator.h"
|
||||
#include <QtCore/QEventLoop>
|
||||
#include <QMimeData>
|
||||
#include <private/qshapedpixmapdndwindow_p.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
static void getTextPlainCallback(val m_string)
|
||||
namespace {
|
||||
Qt::DropAction parseDropActions(emscripten::val event)
|
||||
{
|
||||
QWasmDrag *thisDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag());
|
||||
thisDrag->m_mimeData->setText(QString::fromStdString(m_string.as<std::string>()));
|
||||
thisDrag->qWasmDrop();
|
||||
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
|
||||
|
||||
static void getTextUrlCallback(val m_string)
|
||||
{
|
||||
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)
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
std::string dEffect = event["dataTransfer"]["dropEffect"].as<std::string>();
|
||||
|
||||
wasmDrag->m_dropActions = Qt::IgnoreAction;
|
||||
if (dEffect == "copy")
|
||||
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"];
|
||||
|
||||
val typesCount = event["dataTransfer"]["types"]["length"];
|
||||
|
||||
// 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")) {
|
||||
static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr;
|
||||
readDataCancellation = qstdweb::readDataTransfer(
|
||||
event["dataTransfer"],
|
||||
[](QByteArray fileContent) {
|
||||
QImage image;
|
||||
image.loadFromData(fileContent, nullptr);
|
||||
wasmDrag->m_mimeData->setImageData(image);
|
||||
} else {
|
||||
wasmDrag->m_mimeData->setData(mimeFormat, fileContent.data());
|
||||
}
|
||||
wasmDrag->qWasmDrop();
|
||||
}
|
||||
});
|
||||
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);
|
||||
|
||||
} 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) {
|
||||
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);
|
||||
QWindowSystemInterface::handleDrag(window, data.get(), mouseDropPoint, dropAction,
|
||||
button, modifiers);
|
||||
|
||||
// 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);
|
||||
QWindowSystemInterface::handleDrop(window, data.get(), mouseDropPoint, dropAction,
|
||||
button, modifiers);
|
||||
|
||||
// drag leave
|
||||
QWindowSystemInterface::handleDrag(thisDrag->m_wasmScreen->topLevelAt(thisDrag->m_mouseDropPoint),
|
||||
nullptr,
|
||||
QPoint(),
|
||||
Qt::IgnoreAction, { }, { });
|
||||
QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, {},
|
||||
{});
|
||||
});
|
||||
}
|
||||
|
||||
thisDrag->m_mimeData->clear();
|
||||
thisDrag->m_mimeTypesCount = 0;
|
||||
EMSCRIPTEN_BINDINGS(drop_module)
|
||||
{
|
||||
function("qtDrop", &dropEvent);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -4,39 +4,13 @@
|
||||
#ifndef QWASMDRAG_H
|
||||
#define QWASMDRAG_H
|
||||
|
||||
#include <qpa/qplatformdrag.h>
|
||||
#include <private/qsimpledrag_p.h>
|
||||
#include <private/qstdweb_p.h>
|
||||
#include <QDrag>
|
||||
#include "qwasmscreen.h"
|
||||
#include <QtCore/qtconfigmacros.h>
|
||||
|
||||
QT_REQUIRE_CONFIG(draganddrop);
|
||||
#include <emscripten/val.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWasmDrag : public QSimpleDrag
|
||||
{
|
||||
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();
|
||||
};
|
||||
|
||||
void dropEvent(emscripten::val event);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
@ -81,6 +81,12 @@ 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>();
|
||||
@ -122,7 +128,7 @@ QWasmIntegration::QWasmIntegration()
|
||||
visualViewport.call<void>("addEventListener", val("resize"),
|
||||
val::module_property("qtResizeAllScreens"));
|
||||
}
|
||||
m_drag = new QWasmDrag();
|
||||
m_drag = std::make_unique<QSimpleDrag>();
|
||||
}
|
||||
|
||||
QWasmIntegration::~QWasmIntegration()
|
||||
@ -139,7 +145,6 @@ QWasmIntegration::~QWasmIntegration()
|
||||
delete m_desktopServices;
|
||||
if (m_platformInputContext)
|
||||
delete m_platformInputContext;
|
||||
delete m_drag;
|
||||
delete m_accessibility;
|
||||
|
||||
for (const auto &elementAndScreen : m_screens)
|
||||
@ -328,7 +333,7 @@ quint64 QWasmIntegration::getTimestamp()
|
||||
#if QT_CONFIG(draganddrop)
|
||||
QPlatformDrag *QWasmIntegration::drag() const
|
||||
{
|
||||
return m_drag;
|
||||
return m_drag.get();
|
||||
}
|
||||
#endif // QT_CONFIG(draganddrop)
|
||||
|
||||
|
@ -6,23 +6,25 @@
|
||||
|
||||
#include "qwasmwindow.h"
|
||||
|
||||
#include "qwasminputcontext.h"
|
||||
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#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>
|
||||
#include <private/qstdweb_p.h>
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include "qwasminputcontext.h"
|
||||
#include <private/qstdweb_p.h>
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
#include "qwasmdrag.h"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWasmEventTranslator;
|
||||
@ -97,7 +99,7 @@ private:
|
||||
mutable QWasmInputContext *m_platformInputContext = nullptr;
|
||||
|
||||
#if QT_CONFIG(draganddrop)
|
||||
QWasmDrag *m_drag;
|
||||
std::unique_ptr<QSimpleDrag> m_drag;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user