diff options
author | Lorn Potter <[email protected]> | 2022-04-04 18:08:41 +1000 |
---|---|---|
committer | Morten Johan Sørvig <[email protected]> | 2022-05-10 01:20:45 +0000 |
commit | d490501641b1f3990382d3ad3523233fdbf3da61 (patch) | |
tree | 4b52e4e083c0175a9dad058b8c40345747f8955f /src/plugins/platforms/wasm/qwasmdrag.cpp | |
parent | 877c158c5976bebffd0ff02c39b6b66a842c6344 (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.cpp | 236 |
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 |