11#include <qpa/qwindowsysteminterface.h>
13#include <QtCore/private/qstdweb_p.h>
14#include <QtCore/qeventloop.h>
15#include <QtCore/qmimedata.h>
16#include <QtCore/qtimer.h>
29 QWindow *window = qobject_cast<QWindow *>(drag->source());
32 if (drag->source()->metaObject()->indexOfMethod(
"_q_closestWindowHandle()") == -1)
35 QMetaObject::invokeMethod(drag->source(),
"_q_closestWindowHandle",
36 Q_RETURN_ARG(QWindow *, window));
47 DragImage(
const QPixmap &pixmap,
const QMimeData *mimeData, QWindow *window);
53 emscripten::val generateDragImage(
const QPixmap &pixmap,
const QMimeData *mimeData);
54 emscripten::val generateDragImageFromText(
const QMimeData *mimeData);
56 emscripten::val generateDragImageFromPixmap(
const QPixmap &pixmap);
62 DragState(QDrag *drag, QWindow *window,
std::function<
void()> quitEventLoopClosure);
87 Q_ASSERT_X(!m_dragState, Q_FUNC_INFO,
"Drag already in progress");
89 QWindow *window = windowForDrag(drag);
91 return Qt::IgnoreAction;
93 Qt::DropAction dragResult = Qt::IgnoreAction;
94 if (qstdweb::haveJspi()) {
96 m_dragState = std::make_unique<DragState>(drag, window, [&loop]() { loop.quit(); });
98 dragResult = m_dragState->dropAction;
102 if (dragResult == Qt::IgnoreAction)
103 dragResult = QBasicDrag::drag(drag);
110 Q_ASSERT_X(event->type == EventType::DragStart, Q_FUNC_INFO,
111 "The event is not a DragStart event");
113 event->webEvent.call<
void>(
"preventDefault");
116 if (!m_dragState || m_dragState->window != event->targetWindow) {
121 m_dragState->dragImage = std::make_unique<DragState::DragImage>(
122 m_dragState->drag->pixmap(), m_dragState->drag->mimeData(), event->targetWindow);
123 event->dataTransfer.setDragImage(m_dragState->dragImage->htmlElement(),
124 m_dragState->drag->hotSpot());
125 event->dataTransfer.setDataFromMimeData(*m_dragState->drag->mimeData());
130 event->webEvent.call<
void>(
"preventDefault");
132 auto mimeDataPreview = event->dataTransfer.toMimeDataPreview();
134 const Qt::DropActions actions = m_dragState
135 ? m_dragState->drag->supportedActions()
136 : (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
137 | Qt::DropAction::LinkAction);
139 const auto dragResponse = QWindowSystemInterface::handleDrag(
140 event->targetWindow, &*mimeDataPreview, event->pointInPage.toPoint(), actions,
141 event->mouseButton, event->modifiers);
143 if (dragResponse.isAccepted()) {
144 event->dataTransfer.setDropAction(dragResponse.acceptedAction());
146 event->dataTransfer.setDropAction(Qt::DropAction::IgnoreAction);
152 event->webEvent.call<
void>(
"preventDefault");
156 const auto screenElementPos = dom::mapPoint(
158 const auto screenPos =
160 const QPoint targetWindowPos = event->targetWindow->mapFromGlobal(screenPos).toPoint();
162 const Qt::DropActions actions = m_dragState
163 ? m_dragState->drag->supportedActions()
164 : (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
165 | Qt::DropAction::LinkAction);
166 Qt::MouseButton mouseButton = event->mouseButton;
167 QFlags<Qt::KeyboardModifier> modifiers = event->modifiers;
174 const auto dropCallback = [&m_dragState = m_dragState, wasmWindow, targetWindowPos,
175 actions, mouseButton, modifiers](QMimeData *mimeData) {
177 auto dropResponse = std::make_shared<QPlatformDropQtResponse>(
true, Qt::DropAction::CopyAction);
178 *dropResponse = QWindowSystemInterface::handleDrop(wasmWindow->window(), mimeData,
179 targetWindowPos, actions,
180 mouseButton, modifiers);
182 if (dropResponse->isAccepted())
183 m_dragState->dropAction = dropResponse->acceptedAction();
188 event->dataTransfer.toMimeDataWithFile(dropCallback);
193 event->webEvent.call<
void>(
"preventDefault");
194 m_dragState->dropAction = event->dropAction;
195 m_dragState->quitEventLoopClosure();
200 event->webEvent.call<
void>(
"preventDefault");
201 m_dragState->dropAction = event->dropAction;
202 event->dataTransfer.setDropAction(Qt::DropAction::IgnoreAction);
209 m_imageDomElement = generateDragImage(pixmap, mimeData);
211 m_imageDomElement.set(
"className",
"hidden-drag-image");
212 m_temporaryImageElementParent.call<
void>(
"appendChild", m_imageDomElement);
217 m_temporaryImageElementParent.call<
void>(
"removeChild", m_imageDomElement);
221 const QMimeData *mimeData)
223 if (!pixmap.isNull())
224 return generateDragImageFromPixmap(pixmap);
225 if (mimeData->hasFormat(
"text/plain"))
226 return generateDragImageFromText(mimeData);
227 return generateDefaultDragImage();
234 emscripten::val::global(
"document")
235 .call<emscripten::val>(
"createElement", emscripten::val(
"span"));
237 constexpr qsizetype MaxCharactersInDragImage = 100;
239 const auto text = QString::fromUtf8(mimeData->data(
"text/plain"));
240 dragImageElement.set(
242 text.first(qMin(qsizetype(MaxCharactersInDragImage), text.length())).toStdString());
243 return dragImageElement;
249 emscripten::val::global(
"document")
250 .call<emscripten::val>(
"createElement", emscripten::val(
"div"));
252 auto innerImgElement = emscripten::val::global(
"document")
253 .call<emscripten::val>(
"createElement", emscripten::val(
"img"));
254 innerImgElement.set(
"src",
255 "data:image/" + std::string(
"svg+xml") +
";base64,"
256 +
std::string(Base64IconStore::get()->getIcon(
257 Base64IconStore::IconType::QtLogo)));
259 constexpr char DragImageSize[] =
"50px";
261 dragImageElement[
"style"].set(
"width", DragImageSize);
262 innerImgElement[
"style"].set(
"width", DragImageSize);
263 dragImageElement[
"style"].set(
"display",
"flex");
265 dragImageElement.call<
void>(
"appendChild", innerImgElement);
266 return dragImageElement;
272 emscripten::val::global(
"document")
273 .call<emscripten::val>(
"createElement", emscripten::val(
"canvas"));
274 dragImageElement.set(
"width", pixmap.width());
275 dragImageElement.set(
"height", pixmap.height());
277 dragImageElement[
"style"].set(
278 "width",
std::to_string(pixmap.width() / pixmap.devicePixelRatio()) +
"px");
279 dragImageElement[
"style"].set(
280 "height",
std::to_string(pixmap.height() / pixmap.devicePixelRatio()) +
"px");
282 auto context2d = dragImageElement.call<
emscripten::val>(
"getContext", emscripten::val(
"2d"));
283 auto imageData = context2d.call<
emscripten::val>(
286 dom::drawImageToWebImageDataArray(pixmap.toImage().convertedTo(QImage::Format::Format_RGBA8888),
287 imageData, QRect(0, 0, pixmap.width(), pixmap.height()));
288 context2d.call<
void>(
"putImageData", imageData, emscripten::val(0), emscripten::val(0));
290 return dragImageElement;
295 return m_imageDomElement;
299 std::function<
void()> quitEventLoopClosure)
\inmodule QtCore\reentrant
DragImage(const QPixmap &pixmap, const QMimeData *mimeData, QWindow *window)
emscripten::val htmlElement()
void onNativeDragFinished(DragEvent *event)
Qt::DropAction drag(QDrag *drag) final
void onNativeDrop(DragEvent *event)
void onNativeDragLeave(DragEvent *event)
void onNativeDragOver(DragEvent *event)
static QWasmDrag * instance()
void onNativeDragStarted(DragEvent *event)
static QWasmIntegration * get()
emscripten::val element() const
static QWasmWindow * fromWindow(const QWindow *window)
friend class QWasmCompositor
QWasmScreen * platformScreen() const
QWindow * windowForDrag(QDrag *drag)
DragState(QWasmDrag &&other)=delete
std::function< void()> quitEventLoopClosure
DragState(QDrag *drag, QWindow *window, std::function< void()> quitEventLoopClosure)
std::unique_ptr< DragImage > dragImage
Qt::DropAction dropAction
DragState(const QWasmDrag &other)=delete
DragState & operator=(QWasmDrag &&other)=delete
DragState & operator=(const QWasmDrag &other)=delete