Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwasmdrag.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qwasmdrag.h"
5
7#include "qwasmdom.h"
8#include "qwasmevent.h"
9#include "qwasmintegration.h"
10
11#include <qpa/qwindowsysteminterface.h>
12
13#include <QtCore/private/qstdweb_p.h>
14#include <QtCore/qeventloop.h>
15#include <QtCore/qmimedata.h>
16#include <QtCore/qtimer.h>
17#include <QFile>
18
19#include <functional>
20#include <string>
21#include <utility>
22
24
25namespace {
26
28{
30 if (window)
31 return window;
32 if (drag->source()->metaObject()->indexOfMethod("_q_closestWindowHandle()") == -1)
33 return nullptr;
34
35 QMetaObject::invokeMethod(drag->source(), "_q_closestWindowHandle",
37 return window;
38}
39
40} // namespace
41
43{
45 {
46 public:
48 ~DragImage();
49
50 emscripten::val htmlElement();
51
52 private:
53 emscripten::val generateDragImage(const QPixmap &pixmap, const QMimeData *mimeData);
54 emscripten::val generateDragImageFromText(const QMimeData *mimeData);
55 emscripten::val generateDefaultDragImage();
56 emscripten::val generateDragImageFromPixmap(const QPixmap &pixmap);
57
58 emscripten::val m_imageDomElement;
59 emscripten::val m_temporaryImageElementParent;
60 };
61
62 DragState(QDrag *drag, QWindow *window, std::function<void()> quitEventLoopClosure);
64 DragState(const QWasmDrag &other) = delete;
68
71 std::function<void()> quitEventLoopClosure;
72 std::unique_ptr<DragImage> dragImage;
74};
75
76QWasmDrag::QWasmDrag() = default;
77
78QWasmDrag::~QWasmDrag() = default;
79
81{
82 return static_cast<QWasmDrag *>(QWasmIntegration::get()->drag());
83}
84
86{
87 Q_ASSERT_X(!m_dragState, Q_FUNC_INFO, "Drag already in progress");
88
89 QWindow *window = windowForDrag(drag);
90 if (!window)
91 return Qt::IgnoreAction;
92
94 if (qstdweb::haveJspi()) {
95 QEventLoop loop;
96 m_dragState = std::make_unique<DragState>(drag, window, [&loop]() { loop.quit(); });
97 loop.exec();
98 dragResult = m_dragState->dropAction;
99 m_dragState.reset();
100 }
101
102 if (dragResult == Qt::IgnoreAction)
103 dragResult = QBasicDrag::drag(drag);
104
105 return dragResult;
106}
107
109{
111 "The event is not a DragStart event");
112 // It is possible for a drag start event to arrive from another window.
113 if (!m_dragState || m_dragState->window != event->targetWindow) {
114 event->cancelDragStart();
115 return;
116 }
117
118 m_dragState->dragImage = std::make_unique<DragState::DragImage>(
119 m_dragState->drag->pixmap(), m_dragState->drag->mimeData(), event->targetWindow);
120 event->dataTransfer.setDragImage(m_dragState->dragImage->htmlElement(),
121 m_dragState->drag->hotSpot());
122 event->dataTransfer.setDataFromMimeData(*m_dragState->drag->mimeData());
123}
124
126{
127 auto mimeDataPreview = event->dataTransfer.toMimeDataPreview();
128
129 const Qt::DropActions actions = m_dragState
130 ? m_dragState->drag->supportedActions()
133
134 const auto dragResponse = QWindowSystemInterface::handleDrag(
135 event->targetWindow, &*mimeDataPreview, event->pointInPage.toPoint(), actions,
136 event->mouseButton, event->modifiers);
137 event->acceptDragOver();
138 if (dragResponse.isAccepted()) {
139 event->dataTransfer.setDropAction(dragResponse.acceptedAction());
140 } else {
141 event->dataTransfer.setDropAction(Qt::DropAction::IgnoreAction);
142 }
143}
144
146{
147 QWasmWindow *wasmWindow = QWasmWindow::fromWindow(event->targetWindow);
148
149 const auto screenElementPos = dom::mapPoint(
150 event->target(), wasmWindow->platformScreen()->element(), event->localPoint);
151 const auto screenPos =
152 wasmWindow->platformScreen()->mapFromLocal(screenElementPos);
153 const QPoint targetWindowPos = event->targetWindow->mapFromGlobal(screenPos).toPoint();
154
155 const Qt::DropActions actions = m_dragState
156 ? m_dragState->drag->supportedActions()
159 Qt::MouseButton mouseButton = event->mouseButton;
160 QFlags<Qt::KeyboardModifier> modifiers = event->modifiers;
161
162 // Accept the native drop event: We are going to async read any dropped
163 // files, but the browser expects that accepted state is set before any
164 // async calls.
165 event->acceptDrop();
166
167 const auto dropCallback = [&m_dragState = m_dragState, wasmWindow, targetWindowPos,
168 actions, mouseButton, modifiers](QMimeData *mimeData) {
169
170 auto dropResponse = std::make_shared<QPlatformDropQtResponse>(true, Qt::DropAction::CopyAction);
171 *dropResponse = QWindowSystemInterface::handleDrop(wasmWindow->window(), mimeData,
172 targetWindowPos, actions,
173 mouseButton, modifiers);
174
175 if (dropResponse->isAccepted())
176 m_dragState->dropAction = dropResponse->acceptedAction();
177
178 delete mimeData;
179 };
180
181 event->dataTransfer.toMimeDataWithFile(dropCallback);
182}
183
185{
186 m_dragState->dropAction = event->dropAction;
187 m_dragState->quitEventLoopClosure();
188}
189
192 : m_temporaryImageElementParent(QWasmWindow::fromWindow(window)->containerElement())
193{
194 m_imageDomElement = generateDragImage(pixmap, mimeData);
195
196 m_imageDomElement.set("className", "hidden-drag-image");
197 m_temporaryImageElementParent.call<void>("appendChild", m_imageDomElement);
198}
199
201{
202 m_temporaryImageElementParent.call<void>("removeChild", m_imageDomElement);
203}
204
205emscripten::val QWasmDrag::DragState::DragImage::generateDragImage(const QPixmap &pixmap,
206 const QMimeData *mimeData)
207{
208 if (!pixmap.isNull())
209 return generateDragImageFromPixmap(pixmap);
210 if (mimeData->hasFormat("text/plain"))
211 return generateDragImageFromText(mimeData);
212 return generateDefaultDragImage();
213}
214
215emscripten::val
216QWasmDrag::DragState::DragImage::generateDragImageFromText(const QMimeData *mimeData)
217{
218 emscripten::val dragImageElement =
219 emscripten::val::global("document")
220 .call<emscripten::val>("createElement", emscripten::val("span"));
221
222 constexpr qsizetype MaxCharactersInDragImage = 100;
223
224 const auto text = QString::fromUtf8(mimeData->data("text/plain"));
225 dragImageElement.set(
226 "innerText",
227 text.first(qMin(qsizetype(MaxCharactersInDragImage), text.length())).toStdString());
228 return dragImageElement;
229}
230
231emscripten::val QWasmDrag::DragState::DragImage::generateDefaultDragImage()
232{
233 emscripten::val dragImageElement =
234 emscripten::val::global("document")
235 .call<emscripten::val>("createElement", emscripten::val("div"));
236
237 auto innerImgElement = emscripten::val::global("document")
238 .call<emscripten::val>("createElement", emscripten::val("img"));
239 innerImgElement.set("src",
240 "data:image/" + std::string("svg+xml") + ";base64,"
241 + std::string(Base64IconStore::get()->getIcon(
243
244 constexpr char DragImageSize[] = "50px";
245
246 dragImageElement["style"].set("width", DragImageSize);
247 innerImgElement["style"].set("width", DragImageSize);
248 dragImageElement["style"].set("display", "flex");
249
250 dragImageElement.call<void>("appendChild", innerImgElement);
251 return dragImageElement;
252}
253
254emscripten::val QWasmDrag::DragState::DragImage::generateDragImageFromPixmap(const QPixmap &pixmap)
255{
256 emscripten::val dragImageElement =
257 emscripten::val::global("document")
258 .call<emscripten::val>("createElement", emscripten::val("canvas"));
259 dragImageElement.set("width", pixmap.width());
260 dragImageElement.set("height", pixmap.height());
261
262 dragImageElement["style"].set(
263 "width", std::to_string(pixmap.width() / pixmap.devicePixelRatio()) + "px");
264 dragImageElement["style"].set(
265 "height", std::to_string(pixmap.height() / pixmap.devicePixelRatio()) + "px");
266
267 auto context2d = dragImageElement.call<emscripten::val>("getContext", emscripten::val("2d"));
268 auto imageData = context2d.call<emscripten::val>(
269 "createImageData", emscripten::val(pixmap.width()), emscripten::val(pixmap.height()));
270
272 imageData, QRect(0, 0, pixmap.width(), pixmap.height()));
273 context2d.call<void>("putImageData", imageData, emscripten::val(0), emscripten::val(0));
274
275 return dragImageElement;
276}
277
279{
280 return m_imageDomElement;
281}
282
288
290
static Base64IconStore * get()
QDrag * drag() const
\inmodule QtGui
Definition qdrag.h:22
QObject * source() const
Returns the source of the drag object.
Definition qdrag.cpp:168
\inmodule QtCore
Definition qeventloop.h:16
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void quit()
Tells the event loop to exit normally.
@ Format_RGBA8888
Definition qimage.h:59
\inmodule QtCore
Definition qmimedata.h:16
virtual bool hasFormat(const QString &mimetype) const
Returns true if the object can return data for the MIME type specified by mimeType; otherwise returns...
QByteArray data(const QString &mimetype) const
Returns the data stored in the object in the format described by the MIME type specified by mimeType.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
virtual void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
Definition qstring.h:1444
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QString first(qsizetype n) const &
Definition qstring.h:390
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
DragImage(const QPixmap &pixmap, const QMimeData *mimeData, QWindow *window)
void onNativeDragFinished(DragEvent *event)
void onNativeDrop(DragEvent *event)
void onNativeDragOver(DragEvent *event)
~QWasmDrag() override
static QWasmDrag * instance()
Definition qwasmdrag.cpp:80
void onNativeDragStarted(DragEvent *event)
static QWasmIntegration * get()
static QWasmWindow * fromWindow(QWindow *window)
\inmodule QtGui
Definition qwindow.h:63
EGLImageKHR int int EGLuint64KHR * modifiers
QString text
Combined button and popup list for selecting options.
QWindow * windowForDrag(QDrag *drag)
Definition qwasmdrag.cpp:27
MouseButton
Definition qnamespace.h:56
DropAction
@ CopyAction
@ IgnoreAction
@ MoveAction
@ LinkAction
QPointF mapPoint(emscripten::val source, emscripten::val target, const QPointF &point)
Definition qwasmdom.cpp:250
void drawImageToWebImageDataArray(const QImage &sourceImage, emscripten::val destinationImageData, const QRect &sourceRect)
Definition qwasmdom.cpp:261
bool haveJspi()
Definition qstdweb.cpp:823
#define Q_FUNC_INFO
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define Q_RETURN_ARG(Type, data)
Definition qobjectdefs.h:64
struct _cl_event * event
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
ptrdiff_t qsizetype
Definition qtypes.h:165
QWindow * qobject_cast< QWindow * >(QObject *o)
Definition qwindow.h:367
QMimeData * mimeData
QSharedPointer< T > other(t)
[5]
QByteArray imageData
[15]
widget render & pixmap
aWidget window() -> setWindowTitle("New Window Title")
[2]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
DragState(QWasmDrag &&other)=delete
std::unique_ptr< DragImage > dragImage
Definition qwasmdrag.cpp:72
DragState(QDrag *drag, QWindow *window, std::function< void()> quitEventLoopClosure)
std::function< void()> quitEventLoopClosure
Definition qwasmdrag.cpp:71
Qt::DropAction dropAction
Definition qwasmdrag.cpp:73
DragState(const QWasmDrag &other)=delete
DragState & operator=(QWasmDrag &&other)=delete
DragState & operator=(const QWasmDrag &other)=delete