87 constexpr auto dataTypeMaxLength = 128;
89 auto dataTypeCount = getDragEventDataTypeCount(dragEvent);
90 if (dataTypeCount == 0)
93 std::vector<std::array<
char, dataTypeMaxLength + 1>> dataTypesStringData;
94 dataTypesStringData.resize(dataTypeCount);
96 std::vector<
char *> dataTypesStringPointers;
97 for (
std::int32_t i = 0; i < dataTypeCount; ++i)
98 dataTypesStringPointers.push_back(dataTypesStringData[i].data());
100 QArkUi::callArkUiOrFailOnErrorResult(
101 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragEvent_GetDataTypes),
102 dragEvent, dataTypesStringPointers.data(), dataTypesStringPointers.size(), dataTypeMaxLength);
104 return {dataTypesStringPointers.begin(), dataTypesStringPointers.end()};
140 static const std::pair<std::uint64_t, Qt::KeyboardModifier> arkUiToQtModifiersMap[] = {
141 {::ARKUI_MODIFIER_KEY_CTRL, Qt::KeyboardModifier::ControlModifier},
142 {::ARKUI_MODIFIER_KEY_SHIFT, Qt::KeyboardModifier::ShiftModifier},
143 {::ARKUI_MODIFIER_KEY_ALT, Qt::KeyboardModifier::AltModifier},
144 {::ARKUI_MODIFIER_KEY_FN, Qt::KeyboardModifier::MetaModifier},
147 Qt::KeyboardModifiers modifiers;
148 for (
const auto &mod : arkUiToQtModifiersMap)
149 modifiers.setFlag(mod.second, (modifierKeyStates & mod.first) != 0);
203 QOhosSupplier<std::unique_ptr<QMimeData>> dropDataFactory,
std::int32_t pendingDropRequestId)
205 qOhosPrintfDebug(
"%s: async processing of drop request with id=%d", Q_FUNC_INFO, pendingDropRequestId);
207 auto qtDropActionConsumer = moveToSharedPtr(
208 QtOhos::makeCallOnceConsumerWrapper<QtOhos::JsState &, Qt::DropAction>(
209 [pendingDropRequestId](QtOhos::JsState &, Qt::DropAction qtDropAction) {
211 "%s: got qtDropAction=%d for drop request with id=%d",
212 Q_FUNC_INFO,
static_cast<
int>(qtDropAction), pendingDropRequestId);
213 QArkUi::callArkUiOrFailOnErrorResult(
214 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NotifyDragResult),
215 pendingDropRequestId,
216 qtDropAction != Qt::IgnoreAction
217 ? ::ARKUI_DRAG_RESULT_SUCCESSFUL
218 : ::ARKUI_DRAG_RESULT_FAILED);
219 QArkUi::callArkUiOrFailOnErrorResult(
220 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NotifyDragEndPendingDone),
221 pendingDropRequestId);
224 constexpr auto notifyDragEndPendingTimeout = ch::milliseconds(1500);
228 if ((*qtDropActionConsumer)(cbInfo
.jsState(), Qt::IgnoreAction))
229 qOhosPrintfDebug(
"%s: used timeout action for drop request with id=%d", Q_FUNC_INFO, pendingDropRequestId);
231 notifyDragEndPendingTimeout
);
233 qWindowRef.visitInQtThreadIfAlive(
234 [dragEventInfo, dropDataFactory = std::move(dropDataFactory), qtDropActionConsumer](QWindow &qWindow)
mutable {
235 auto dropAction = processDropInQWindow(qWindow, dragEventInfo, std::move(dropDataFactory));
238 (*qtDropActionConsumer)(jsState, dropAction);
250 QtOhos::
JsState &jsState, ::ArkUI_DragEvent *dragEvent, QtOhos::QThreadSafeRef<QWindow> qWindowRef,
251 const DragEventInfo &dragEventInfo, QOhosSupplier<std::unique_ptr<QMimeData>> dropDataFactory)
256 std::int32_t pendingDropRequestId = 0;
257 QArkUi::callArkUiOrFailOnErrorResult(
258 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragEvent_RequestDragEndPending),
259 dragEvent, &pendingDropRequestId);
260 processPendingDropRequestAsynchronously(
261 jsState, qWindowRef, dragEventInfo,
262 std::move(dropDataFactory), pendingDropRequestId);
311 const DragEventInfo &dragEventInfo, QOhosSupplier<std::unique_ptr<QMimeData>> dropDataFactory)
314 constexpr auto answerWaitTimeout = ch::milliseconds(5);
315 constexpr auto waitCooldownAfterTimeout = ch::milliseconds(200);
317 const auto requestId = ++m_lastRequestId;
319 [dragEventInfo, dropDataFactory = std::move(dropDataFactory),
320 sharedDropActionState = m_sharedDropActionState, requestId](QWindow &qWindow) {
321 QDrag *currentDrag = QDragManager::self()->object();
322 QPlatformDragQtResponse qtResponse = QWindowSystemInterface::handleDrag(
324 currentDrag !=
nullptr ? currentDrag->mimeData() : dropDataFactory().get(),
325 dragEventInfo.localDropPos,
326 currentDrag !=
nullptr ? currentDrag->supportedActions() : dragEventInfo.dropActions,
327 Qt::LeftButton, dragEventInfo.keyboardModifiers);
328 if (currentDrag !=
nullptr && qtResponse.isAccepted() && qtResponse.acceptedAction() != Qt::IgnoreAction)
332 std::lock_guard<
std::mutex> stateLock(sharedDropActionState->mutex);
333 if (requestId <= sharedDropActionState->answeredRequestId)
336 sharedDropActionState->answeredRequestId = requestId;
337 sharedDropActionState->optDropAction = qtResponse.acceptedAction();
339 sharedDropActionState->answerCondVar.notify_all();
342 m_pendingQueryUpdater(
343 [&](std::function<
void(QWindow &)> &pendingQuery) {
344 pendingQuery = std::move(queryFunc);
347 const auto now = ch::steady_clock::now();
348 const bool waitingMakesSense =
349 !m_optLastFailedWaitTime || now - m_optLastFailedWaitTime.value() >= waitCooldownAfterTimeout;
352 std::unique_lock<
std::mutex> stateLock(m_sharedDropActionState->mutex);
353 if (waitingMakesSense) {
354 const bool answered = m_sharedDropActionState->answerCondVar.wait_for(
355 stateLock, answerWaitTimeout,
357 return m_sharedDropActionState->answeredRequestId >= requestId;
360 m_optLastFailedWaitTime.reset();
362 m_optLastFailedWaitTime = now;
365 return m_sharedDropActionState->optDropAction;
379 QtOhos::QThreadSafeRef<QWindow> qWindowRef)
381 auto eventsHandler = [qWindowRef, dragMoveResponder = DragMoveResponder(qWindowRef)](
382 QtOhos::JsState &jsState, ::ArkUI_NodeEvent *nodeEvent)
mutable {
383 auto eventType = QArkUi::callArkUi(Q_OHOS_NAMED_FUNC(OH_ArkUI_NodeEvent_GetEventType), nodeEvent);
384 auto *dragEvent = QArkUi::callArkUiOrFailOnNullResult(Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeEvent_GetDragEvent), nodeEvent);
385 auto node = QArkUi::callArkUiOrFailOnNullResult(Q_OHOS_NAMED_FUNC(OH_ArkUI_NodeEvent_GetNodeHandle), nodeEvent);
387 auto touchDisplayPosition = getDragEventTouchDisplayPosition(dragEvent);
388 auto nodeDisplayPosition = QArkUi::Node::nodeDisplayPosition(node);
389 auto localPosition = touchDisplayPosition - nodeDisplayPosition;
391 DragEventInfo dragEventInfo = {
392 .localDropPos = localPosition,
393 .dropActions = mapQOhosArkUiDropOperationToQt(getQOhosDragEventDropOperation(dragEvent)),
394 .keyboardModifiers = mapArkUiModifierKeyStatesToQt(getDragEventModifierKeyStates(dragEvent)),
397 qOhosPrintfDebug(
"QNativeNode: got drag event: %d, (%d,%d)", eventType, dragEventInfo.localDropPos.x(), dragEventInfo.localDropPos.y());
400 case ::NODE_ON_DRAG_ENTER:
401 dragMoveResponder.forgetLastDropAction();
403 case ::NODE_ON_DRAG_MOVE:
405 auto qtDropAction = dragMoveResponder.respondToMove(
407 makeDummyQMimeDataFactoryFromUdmfDataTypes(getDragEventDataTypes(dragEvent)));
408 QArkUi::callArkUiOrFailOnErrorResult(
409 Q_OHOS_NAMED_FUNC(::qOhosSetArkUiDragEventDragResult),
411 static_cast<std::uint32_t>(
412 qtDropAction.value_or(Qt::IgnoreAction) != Qt::IgnoreAction
413 ? DropStatus::Enabled
414 : DropStatus::Disabled));
415 setDragEventSuggestedDropOperationIfAvailable(
416 dragEvent, qAndThen(qtDropAction, &tryMapQOhosArkUiDropOperationFromQt));
419 case ::NODE_ON_DRAG_LEAVE:
420 qWindowRef.visitInQtThreadIfAlive(
421 [](QWindow &qWindow) {
422 std::ignore = QWindowSystemInterface::handleDrag(
423 &qWindow,
nullptr, QPoint(), Qt::IgnoreAction, Qt::MouseButtons(), Qt::KeyboardModifiers());
428 QOhosSupplier<std::unique_ptr<QMimeData>> dropDataFactory;
429 if (getDragEventDataTypeCount(dragEvent) != 0) {
430 auto optDragUdmfData = tryGetDragEventUdmfDataOrNull(dragEvent);
431 dropDataFactory = optDragUdmfData
432 ? createQMimeDataFactoryFromUdmfData(std::move(*optDragUdmfData))
433 : &std::make_unique<QMimeData>;
435 dropDataFactory = &std::make_unique<QMimeData>;
437 auto copyableDropDataFactory = makeImplicitlySharedSupplier(std::move(dropDataFactory));
439 bool asyncProcessingStarted = tryStartAsyncProcessingOfDropEvent(
440 jsState, dragEvent, qWindowRef, dragEventInfo, copyableDropDataFactory);
442 if (!asyncProcessingStarted) {
443 auto qtDropAction = tryRunInQtThreadAndGetResult<QWindow, Qt::DropAction>(
445 [dragEventInfo, copyableDropDataFactory](QWindow &qWindow) {
446 return processDropInQWindow(qWindow, dragEventInfo, copyableDropDataFactory);
448 QArkUi::callArkUiOrFailOnErrorResult(
449 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragEvent_SetDragResult),
451 qtDropAction.value_or(Qt::IgnoreAction) != Qt::IgnoreAction
452 ? ::ARKUI_DRAG_RESULT_SUCCESSFUL
453 : ::ARKUI_DRAG_RESULT_FAILED);
454 setDragEventSuggestedDropOperationIfAvailable(
455 dragEvent, qAndThen(qtDropAction, &tryMapQOhosArkUiDropOperationFromQt));
464 return [eventsHandler = std::move(eventsHandler)](::ArkUI_NodeEvent *nodeEvent)
mutable {
465 QtOhos::runInJsThreadAndWait(
466 [&](QtOhos::JsState &jsState) {
467 eventsHandler(jsState, nodeEvent);