80 constexpr auto dataTypeMaxLength = 128;
82 auto dataTypeCount = getDragEventDataTypeCount(dragEvent);
83 if (dataTypeCount == 0)
86 std::vector<std::array<
char, dataTypeMaxLength + 1>> dataTypesStringData;
87 dataTypesStringData.resize(dataTypeCount);
89 std::vector<
char *> dataTypesStringPointers;
90 for (
std::int32_t i = 0; i < dataTypeCount; ++i)
91 dataTypesStringPointers.push_back(dataTypesStringData[i].data());
93 QArkUi::callArkUiOrFailOnErrorResult(
94 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragEvent_GetDataTypes),
95 dragEvent, dataTypesStringPointers.data(), dataTypesStringPointers.size(), dataTypeMaxLength);
97 return {dataTypesStringPointers.begin(), dataTypesStringPointers.end()};
133 static const std::pair<std::uint64_t, Qt::KeyboardModifier> arkUiToQtModifiersMap[] = {
134 {::ARKUI_MODIFIER_KEY_CTRL, Qt::KeyboardModifier::ControlModifier},
135 {::ARKUI_MODIFIER_KEY_SHIFT, Qt::KeyboardModifier::ShiftModifier},
136 {::ARKUI_MODIFIER_KEY_ALT, Qt::KeyboardModifier::AltModifier},
137 {::ARKUI_MODIFIER_KEY_FN, Qt::KeyboardModifier::MetaModifier},
140 Qt::KeyboardModifiers modifiers;
141 for (
const auto &mod : arkUiToQtModifiersMap)
142 modifiers.setFlag(mod.second, (modifierKeyStates & mod.first) != 0);
170 QtOhos::QThreadSafeRef<Context> contextRef,
171 QOhosSupplier<ch::nanoseconds> timeoutsSupplier)
173 auto batchUpdater = makeQtOhosBatchingMTRequestsHandler<std::function<
void(Context &)>>(
174 [contextRef](std::function<
void()> task) {
175 contextRef.visitInQtThreadIfAlive([task = std::move(task)](Context &) {
179 [contextRef](std::function<
void(Context &)> &&request) {
180 request(*contextRef.data());
183 struct ExecutorContext {
184 decltype(batchUpdater) batchUpdater;
185 QOhosSupplier<ch::nanoseconds> timeoutsSupplier;
188 auto executorContext = QtOhos::moveToSharedPtr(
190 .batchUpdater = std::move(batchUpdater),
191 .timeoutsSupplier = std::move(timeoutsSupplier),
194 return [executorContext](std::function<Result(Context &)> qtThreadProcessFunc) {
195 const auto maxResultWaitTime = executorContext->timeoutsSupplier();
197 auto promise = std::make_shared<std::promise<Result>>();
198 auto future = promise->get_future();
200 executorContext->batchUpdater(
201 [&](std::function<
void(Context &)> &request) {
202 request = [qtThreadProcessFunc = std::move(qtThreadProcessFunc), promise](Context &context) {
203 promise->set_value(qtThreadProcessFunc(context));
207 return future.wait_for(maxResultWaitTime) == std::future_status::ready
208 ? makeQOhosOptional(future.get())
209 : makeEmptyQOhosOptional();
243 QOhosSupplier<std::unique_ptr<QMimeData>> dropDataFactory,
std::int32_t pendingDropRequestId)
245 qOhosPrintfDebug(
"%s: async processing of drop request with id=%d", Q_FUNC_INFO, pendingDropRequestId);
247 auto qtDropActionConsumer = moveToSharedPtr(
248 QtOhos::makeCallOnceConsumerWrapper<QtOhos::JsState &, Qt::DropAction>(
249 [pendingDropRequestId](QtOhos::JsState &, Qt::DropAction qtDropAction) {
251 "%s: got qtDropAction=%d for drop request with id=%d",
252 Q_FUNC_INFO,
static_cast<
int>(qtDropAction), pendingDropRequestId);
253 QArkUi::callArkUiOrFailOnErrorResult(
254 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NotifyDragResult),
255 pendingDropRequestId,
256 qtDropAction != Qt::IgnoreAction
257 ? ::ARKUI_DRAG_RESULT_SUCCESSFUL
258 : ::ARKUI_DRAG_RESULT_FAILED);
259 QArkUi::callArkUiOrFailOnErrorResult(
260 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NotifyDragEndPendingDone),
261 pendingDropRequestId);
264 constexpr auto notifyDragEndPendingTimeout = ch::milliseconds(1500);
268 if ((*qtDropActionConsumer)(cbInfo
.jsState(), Qt::IgnoreAction))
269 qOhosPrintfDebug(
"%s: used timeout action for drop request with id=%d", Q_FUNC_INFO, pendingDropRequestId);
271 notifyDragEndPendingTimeout
);
273 qWindowRef.visitInQtThreadIfAlive(
274 [dragEventInfo, dropDataFactory = std::move(dropDataFactory), qtDropActionConsumer](QWindow &qWindow)
mutable {
275 auto dropAction = processDropInQWindow(qWindow, dragEventInfo, std::move(dropDataFactory));
278 (*qtDropActionConsumer)(jsState, dropAction);
333 QtOhos::QThreadSafeRef<QWindow> qWindowRef)
335 auto qtThreadMoveEventsProcessor = makeBestEffortQtThreadFunctionsExecutor<QWindow, Qt::DropAction>(
336 qWindowRef, makeDragMoveQtThreadWaitTimeoutsSupplier());
337 auto eventsHandler = [qWindowRef, qtThreadMoveEventsProcessor = std::move(qtThreadMoveEventsProcessor)](
338 QtOhos::JsState &jsState, ::ArkUI_NodeEventType eventType, ::ArkUI_DragEvent *dragEvent) {
339 DragEventInfo dragEventInfo = {
340 .globalDropPos = QPoint(
341 ::OH_ArkUI_DragEvent_GetTouchPointXToDisplay(dragEvent),
342 ::OH_ArkUI_DragEvent_GetTouchPointYToDisplay(dragEvent)),
343 .dropActions = mapQOhosArkUiDropOperationToQt(getQOhosDragEventDropOperation(dragEvent)),
344 .keyboardModifiers = mapArkUiModifierKeyStatesToQt(getDragEventModifierKeyStates(dragEvent)),
347 qOhosPrintfDebug(
"QNativeNode: got drag event: %d, (%d,%d)", eventType, dragEventInfo.globalDropPos.x(), dragEventInfo.globalDropPos.y());
350 case ::NODE_ON_DRAG_ENTER:
351 case ::NODE_ON_DRAG_MOVE:
353 auto dropDataFactory = makeDummyQMimeDataFactoryFromUdmfDataTypes(
354 getDragEventDataTypes(dragEvent));
355 auto qtDropAction = qtThreadMoveEventsProcessor(
356 [dragEventInfo, dropDataFactory = std::move(dropDataFactory)](QWindow &qWindow) {
357 QDrag *currentDrag = QDragManager::self()->object();
358 QPlatformDragQtResponse qtResponse = QWindowSystemInterface::handleDrag(
360 currentDrag !=
nullptr ? currentDrag->mimeData() : dropDataFactory().get(),
361 QHighDpi::toNativeLocalPosition(
362 qWindow.mapFromGlobal(QHighDpi::fromNativePixels(dragEventInfo.globalDropPos, &qWindow)), &qWindow),
363 currentDrag !=
nullptr ? currentDrag->supportedActions() : dragEventInfo.dropActions,
364 Qt::LeftButton, dragEventInfo.keyboardModifiers);
365 if (currentDrag !=
nullptr && qtResponse.isAccepted() && qtResponse.acceptedAction() != Qt::IgnoreAction)
366 getQOhosPlatformDrag()->updateDropAction(qtResponse.acceptedAction());
367 return qtResponse.acceptedAction();
369 QArkUi::callArkUiOrFailOnErrorResult(
370 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragEvent_SetDragResult),
372 qtDropAction.valueOr(Qt::IgnoreAction) != Qt::IgnoreAction
375 setDragEventSuggestedDropOperationIfAvailable(
376 dragEvent, qtDropAction.andThen(&tryMapQOhosArkUiDropOperationFromQt));
379 case ::NODE_ON_DRAG_LEAVE:
380 qWindowRef.visitInQtThreadIfAlive(
381 [](QWindow &qWindow) {
382 std::ignore = QWindowSystemInterface::handleDrag(
383 &qWindow,
nullptr, QPoint(), Qt::IgnoreAction, Qt::MouseButtons(), Qt::KeyboardModifiers());
388 QOhosSupplier<std::unique_ptr<QMimeData>> dropDataFactory;
389 if (getDragEventDataTypeCount(dragEvent) != 0) {
390 auto optDragUdmfData = tryGetDragEventUdmfDataOrNull(dragEvent);
391 dropDataFactory = optDragUdmfData
392 ? createQMimeDataFactoryFromUdmfData(std::move(*optDragUdmfData))
393 : &std::make_unique<QMimeData>;
395 dropDataFactory = &std::make_unique<QMimeData>;
397 auto copyableDropDataFactory = makeImplicitlySharedSupplier(std::move(dropDataFactory));
399 bool asyncProcessingStarted = tryStartAsyncProcessingOfDropEvent(
400 jsState, dragEvent, qWindowRef, dragEventInfo, copyableDropDataFactory);
402 if (!asyncProcessingStarted) {
403 auto qtDropAction = tryRunInQtThreadAndGetResult<QWindow, Qt::DropAction>(
405 [dragEventInfo, copyableDropDataFactory](QWindow &qWindow) {
406 return processDropInQWindow(qWindow, dragEventInfo, copyableDropDataFactory);
408 QArkUi::callArkUiOrFailOnErrorResult(
409 Q_OHOS_NAMED_FUNC(::OH_ArkUI_DragEvent_SetDragResult),
411 qtDropAction.valueOr(Qt::IgnoreAction) != Qt::IgnoreAction
412 ? ::ARKUI_DRAG_RESULT_SUCCESSFUL
413 : ::ARKUI_DRAG_RESULT_FAILED);
414 setDragEventSuggestedDropOperationIfAvailable(
415 dragEvent, qtDropAction.andThen(&tryMapQOhosArkUiDropOperationFromQt));
424 return [eventsHandler = std::move(eventsHandler)](::ArkUI_NodeEventType eventType, ::ArkUI_DragEvent *dragEvent) {
425 QtOhos::runInJsThreadAndWait(
426 [&](QtOhos::JsState &jsState) {
427 eventsHandler(jsState, eventType, dragEvent);