summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/wasm/qwasmdrag.cpp
diff options
context:
space:
mode:
authorLorn Potter <[email protected]>2022-04-04 18:08:41 +1000
committerMorten Johan Sørvig <[email protected]>2022-05-10 01:20:45 +0000
commitd490501641b1f3990382d3ad3523233fdbf3da61 (patch)
tree4b52e4e083c0175a9dad058b8c40345747f8955f /src/plugins/platforms/wasm/qwasmdrag.cpp
parent877c158c5976bebffd0ff02c39b6b66a842c6344 (diff)
wasm: add support for drag into browser window
Drag and drop into the browser will work. Drag and drop out of the browser will not. Fixes: QTBUG-102242 Change-Id: Id9981ab6f9514535e1409bec18068790833a67a6 Reviewed-by: Morten Johan Sørvig <[email protected]>
Diffstat (limited to 'src/plugins/platforms/wasm/qwasmdrag.cpp')
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/src/plugins/platforms/wasm/qwasmdrag.cpp b/src/plugins/platforms/wasm/qwasmdrag.cpp
new file mode 100644
index 00000000000..a6cd1d388f9
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdrag.cpp
@@ -0,0 +1,236 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwasmdrag.h"
+
+#include <iostream>
+#include <QMimeDatabase>
+
+#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>
+
+QT_BEGIN_NAMESPACE
+
+using namespace emscripten;
+
+static void getTextPlainCallback(val m_string)
+{
+ QWasmDrag *thisDrag = static_cast<QWasmDrag*>(QWasmIntegration::get()->drag());
+ thisDrag->m_mimeData->setText(QString::fromStdString(m_string.as<std::string>()));
+ thisDrag->qWasmDrop();
+}
+
+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)
+{
+ // 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;
+ int button = event["button"].as<int>();
+ wasmDrag->m_qButton = QWasmEventTranslator::translateMouseButton(button);
+
+ 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(), [=]() {
+ if (!fileContent.isEmpty()) {
+
+ 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) {
+ 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