Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohoswindowproxy.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <render/qohoswindowproxy.h>
5
6#include <QtCore/qcoreapplication.h>
7#include <QtCore/qset.h>
8#include <QtCore/private/qnapi_p.h>
9#include <QtCore/qscopeguard.h>
10#include <QtGui/private/qohosimageconversions_p.h>
11#include <QtGui/qguiapplication.h>
12#include <QtGui/qimage.h>
13#include <algorithm>
14#include <functional>
15#include <memory>
16#include <multimedia/image_framework/image/pixelmap_native.h>
17#include <qarkui/input.h>
18#include <qarkui/qarkuiutils.h>
19#include <qarkui/qxcomponentregistry.h>
20#include <qarkui/window.h>
21#include <qarkui/window_manager.h>
22#include <qohosdeviceinfo_p.h>
23#include <qohosdisplayinfo.h>
24#include <qohosjsutils.h>
25#include <qohospixelmapconversions.h>
26#include <qohosplugincore.h>
27#include <qohosqpaenums.h>
28#include <qohossettings.h>
29#include <qohosutils.h>
30#include <render/qohosbatchingrequestshandler.h>
31#include <render/qohosjswindowregistry.h>
32#include <render/qohoswindowproxydatafactory.h>
33#include <render/qxcomponent.h>
34#include <type_traits>
35
37
38namespace
39{
40
42
43QRect ohosWindowRectToQRect(const QNapi::Object &ohosWindowRect)
44{
45 return QRect {
46 ohosWindowRect.get<QNapi::Number>("left"),
47 ohosWindowRect.get<QNapi::Number>("top"),
48 ohosWindowRect.get<QNapi::Number>("width"),
49 ohosWindowRect.get<QNapi::Number>("height"),
50 };
51}
52
53QOhosWindowProxy::AvoidArea mapAvoidAreaFromJs(const QNapi::Object &avoidAreaObject)
54{
55 return {
56 .visible = avoidAreaObject.get<QNapi::Boolean>("visible"),
57 .leftRect = ohosWindowRectToQRect(avoidAreaObject.get<QNapi::Object>("leftRect")),
58 .topRect = ohosWindowRectToQRect(avoidAreaObject.get<QNapi::Object>("topRect")),
59 .rightRect = ohosWindowRectToQRect(avoidAreaObject.get<QNapi::Object>("rightRect")),
60 .bottomRect = ohosWindowRectToQRect(avoidAreaObject.get<QNapi::Object>("bottomRect")),
61 };
62}
63
65{
66 switch (shape) {
67 case Qt::ArrowCursor:
69 case Qt::UpArrowCursor:
71 case Qt::CrossCursor:
73 case Qt::WaitCursor:
75 case Qt::IBeamCursor:
77 case Qt::SizeVerCursor:
79 case Qt::SizeHorCursor:
81 case Qt::SizeBDiagCursor:
83 case Qt::SizeFDiagCursor:
85 case Qt::SizeAllCursor:
87 case Qt::BlankCursor:
88 // TODO: there is no dedicated Ohos 'Qt::BlankCursor'. Return default.
90 case Qt::SplitVCursor:
92 case Qt::SplitHCursor:
94 case Qt::PointingHandCursor:
96 case Qt::ForbiddenCursor:
98 case Qt::WhatsThisCursor:
100 case Qt::BusyCursor:
102 case Qt::OpenHandCursor:
104 case Qt::ClosedHandCursor:
106 case Qt::DragCopyCursor:
108 case Qt::DragMoveCursor:
110 case Qt::DragLinkCursor:
111 // TODO: there is no dedicated Ohos 'Qt::DragLinkCursor'. Return default.
113 case Qt::BitmapCursor:
114 // TODO: there is no dedicated Ohos 'Qt::BitmapCursor'. Return default.
116 case Qt::CustomCursor:
117 // TODO: there is no dedicated Ohos 'Qt::CustomCursor'. Return default.
119 }
120
122}
123
124std::optional<double> getOptionalNumberPropAsOptionalDouble(const QNapi::Object &object, const std::string &propertyName)
125{
126 auto propOrEmpty = QNapi::getOptionalPropOrEmpty<QNapi::Number>(object, propertyName);
127 return !propOrEmpty.IsEmpty()
128 ? std::optional<double>(propOrEmpty)
129 : std::nullopt;
130}
131
133{
134 auto windowPropsObj = jsWindow.eval<QNapi::Object>("getWindowProperties()");
135 auto displayIdOrEmpty = QNapi::getOptionalPropOrEmpty<QNapi::Number>(windowPropsObj, "displayId");
136 return QArkUi::WindowProperties {
137 .windowRect = ohosWindowRectToQRect(windowPropsObj.get<QNapi::Object>("windowRect")),
138 .drawableRect = ohosWindowRectToQRect(windowPropsObj.get<QNapi::Object>("drawableRect")),
139 .id = QArkUi::JsWindowId(windowPropsObj.get<QNapi::Number>("id")),
140 .displayId = !displayIdOrEmpty.IsEmpty()
141 ? std::optional(QOhosDisplayInfo::JsDisplayId{displayIdOrEmpty.DoubleValue()})
142 : std::nullopt,
143 };
144}
145
146QNapi::Object toNapiObject(napi_env env, const QOhosWindowProxy::MoveConfiguration &moveConfiguration)
147{
148 auto moveConfigurationObject = QNapi::makeObject(env);
149 if (moveConfiguration.displayId.has_value()) {
150 moveConfigurationObject.set(
151 "displayId", moveConfiguration.displayId.value().value());
152 }
153 return moveConfigurationObject;
154}
155
156template<typename ...Args>
158 std::function<void(Args...)> QOhosWindowProxy::WindowCallbacks::*memberPtr,
159 std::shared_ptr<QOhosWindowProxy::WindowCallbacks> qtWindowCallbacks)
160{
161 auto weakQtWindowCallbacks = QtOhos::makeWeakPtr(qtWindowCallbacks);
162
163 return [memberPtr, weakQtWindowCallbacks](Args ...args) {
164 QtOhos::invokeInQtThread([memberPtr, weakQtWindowCallbacks, args...]() {
165 auto qtWindowCallbacks = weakQtWindowCallbacks.lock();
166 if (qtWindowCallbacks)
167 (*qtWindowCallbacks.*memberPtr)(args...);
168 });
169 };
170}
171
172template<typename T>
174 std::function<void(T)> QOhosWindowProxy::WindowCallbacks::*memberPtr,
175 std::shared_ptr<QOhosWindowProxy::WindowCallbacks> qtWindowCallbacks)
176{
177 auto weakQtWindowCallbacks = QtOhos::makeWeakPtr(qtWindowCallbacks);
178
179 return QtOhos::makeCompressingAsyncConsumer<T>(
180 [memberPtr, weakQtWindowCallbacks](T value) {
181 auto qtWindowCallbacks = weakQtWindowCallbacks.lock();
182 if (qtWindowCallbacks)
183 (*qtWindowCallbacks.*memberPtr)(value);
184 },
185 QtOhos::invokeInQtThread);
186}
187
188bool isPointInNonClientArea(const QPoint &point, const QArkUi::WindowProperties &windowProperties)
189{
190 constexpr bool containsPolicyExcludeEdgeValue = true;
191
192 auto drawableRectInScreenSpace =
193 windowProperties.drawableRect.translated(windowProperties.windowRect.topLeft());
194 return !drawableRectInScreenSpace.contains(point, containsPolicyExcludeEdgeValue);
195}
196
198{
199 switch (action) {
200 case ::MOUSE_ACTION_MOVE:
201 return QEvent::NonClientAreaMouseMove;
202 case ::MOUSE_ACTION_BUTTON_DOWN:
203 return QEvent::NonClientAreaMouseButtonPress;
204 case ::MOUSE_ACTION_BUTTON_UP:
205 return QEvent::NonClientAreaMouseButtonRelease;
206 case ::MOUSE_ACTION_CANCEL:
207 case ::MOUSE_ACTION_AXIS_BEGIN:
208 case ::MOUSE_ACTION_AXIS_UPDATE:
209 case ::MOUSE_ACTION_AXIS_END:
210 break;
211 }
212 return std::nullopt;
213}
214
215std::optional<Qt::MouseButton> tryMapMouseEventButtonToQt(::Input_MouseEventButton button)
216{
217 switch (button) {
218 case ::MOUSE_BUTTON_LEFT:
219 return Qt::LeftButton;
220 case ::MOUSE_BUTTON_MIDDLE:
221 return Qt::MiddleButton;
222 case ::MOUSE_BUTTON_RIGHT:
223 return Qt::RightButton;
224 case ::MOUSE_BUTTON_FORWARD:
225 return Qt::ForwardButton;
226 case ::MOUSE_BUTTON_BACK:
227 return Qt::BackButton;
228 case ::MOUSE_BUTTON_NONE:
229 break;
230 }
231 return std::nullopt;
232}
233
235{
236 switch (action) {
237 case ::TOUCH_ACTION_MOVE:
238 return QEvent::NonClientAreaMouseMove;
239 case ::TOUCH_ACTION_DOWN:
240 return QEvent::NonClientAreaMouseButtonPress;
241 case ::TOUCH_ACTION_UP:
242 return QEvent::NonClientAreaMouseButtonRelease;
243 case ::TOUCH_ACTION_CANCEL:
244 break;
245 }
246 return std::nullopt;
247}
248
249template<typename EnumsContainer>
250std::string mapEnumsToLogString(const EnumsContainer &enums)
251{
252 std::string output;
253 for (auto enumValue : enums) {
254 if (!output.empty())
255 output += ",";
256 output += std::to_string(static_cast<std::underlying_type_t<decltype(enumValue)>>(enumValue));
257 }
258 return output;
259}
260
261bool isAbilityTerminating(QNapi::Object ability)
262{
263 return ability.eval<QNapi::Boolean>("context.isTerminating()");
264}
265
267 QNapi::Object jsWindow, WindowProxyType windowType, std::shared_ptr<QtOhos::QAbilityPeer> abilityPeer)
268{
269 const bool boundToAbility = windowType != WindowProxyType::FloatWindow;
270 return QtOhos::JsWindowsTracker::isWindowClosing(jsWindow) || (boundToAbility && isAbilityTerminating(abilityPeer->qAbility()));
271}
272
273}
274
275const QOhosWindowProxy::EventHandlerDescriptor QOhosWindowProxy::eventHandlerDescriptors[] = {
276 {
277 .eventName = "avoidAreaChange",
278 .eventHandler = &QOhosWindowProxy::JsScopeData::handleAvoidAreaChangeCallback,
279 .eventHandlerFlags = {},
280 },
281 {
282 .eventName = "touchOutside",
283 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowTouchOutsideCallback,
284 .eventHandlerFlags = {},
285 },
286 {
287 .eventName = "windowEvent",
288 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowEventCallback,
289 .eventHandlerFlags = EventHandlerFlagBits::allowCallWhenAbilityIsTerminating,
290 },
291 {
292 .eventName = "windowRectChange",
293 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowRectChangeCallback,
294 .eventHandlerFlags = {},
295 },
296 {
297 .eventName = "rectChangeInGlobalDisplay",
298 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowRectChangeInGlobalDisplayCallback,
299 .eventHandlerFlags = {},
300 },
301 {
302 .eventName = "windowStatusChange",
303 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowStatusCallback,
304 .eventHandlerFlags = {},
305 },
306 {
307 .eventName = "windowVisibilityChange",
308 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowVisibilityCallback,
309 .eventHandlerFlags = {},
310 },
311 {
312 .eventName = "displayIdChange",
313 .eventHandler = &QOhosWindowProxy::JsScopeData::handleWindowDisplayIdChangeCallback,
314 .eventHandlerFlags = EventHandlerFlagBits::allowEventHandlerRegistrationFailure,
315 },
316};
317
318QOhosWindowProxy::QOhosWindowProxy(
319 const std::function<void(QtOhos::JsState &, QOhosConsumer<QtOhos::JsState &, QOhosWindowProxyData>)> &makeWindowProxyDataInJsThread)
320{
321 auto jsThreadInitResult = QOhosJsThreadGateway::evalWithPromise<JsThreadInitResult>(
322 [&](QOhosJsState &jsState, QOhosTaskPromise<JsThreadInitResult> evalPromise) {
323 auto sharedEvalPromise = QtOhos::moveToSharedPtr(std::move(evalPromise).makeChained(Q_FUNC_INFO));
324 makeWindowProxyDataInJsThread(
325 QtOhos::JsState::castFrom(jsState),
326 [sharedEvalPromise, this](QtOhos::JsState &jsState, QOhosWindowProxyData windowProxyData) {
327 (*sharedEvalPromise)(initInJsThread(jsState, std::move(windowProxyData)));
328 });
329 },
330 Q_FUNC_INFO);
331 m_windowProxyType = jsThreadInitResult.windowProxyType;
332 m_nodeXComponent = std::move(jsThreadInitResult.nodeXComponent);
333 m_qAbilityInstanceId = std::move(jsThreadInitResult.qAbilityInstanceId);
334 m_jsWindowRegistrationHandle = std::move(jsThreadInitResult.jsWindowRegistrationHandle);
335}
336
337QOhosWindowProxy::JsThreadInitResult QOhosWindowProxy::initInJsThread(
338 QtOhos::JsState &jsState, QOhosWindowProxyData windowProxyData)
339{
340 *m_jsScopeData = JsScopeData(
341 windowProxyData.windowProxyType,
342 std::move(windowProxyData.jsWindow),
343 std::move(windowProxyData.jsKeepAliveData),
344 std::move(windowProxyData.qAbilityPeer),
345 windowProxyData.owningQWindowRef);
346
347 std::vector<std::shared_ptr<void>> eventListenersHandles;
348 for (const auto &eventHandlerDescriptor : eventHandlerDescriptors) {
349 eventListenersHandles.push_back(
350 m_jsScopeData->registerEventListener(
351 eventHandlerDescriptor.eventName, eventHandlerDescriptor.eventHandler,
352 eventHandlerDescriptor.eventHandlerFlags));
353 }
354 m_jsScopeData->m_eventListenersHandle = QtOhos::moveToSharedPtr(std::move(eventListenersHandles));
355
356 return JsThreadInitResult {
357 .windowProxyType = windowProxyData.windowProxyType,
358 .nodeXComponent = std::move(windowProxyData.nodeXComponent),
359 .qAbilityInstanceId = m_jsScopeData->jsWindowRef->owningQAbilityInstanceId(),
360 .jsWindowRegistrationHandle = QOhosJsWindowRegistry::instance(jsState).registerJsWindow(m_jsScopeData->jsWindowRef),
361 };
362}
363
364QOhosWindowProxy::~QOhosWindowProxy()
365{
366 // NOTE
367 // we need to unregister from JS Window events now, while the Window is
368 // still in consistent state. While destroying the m_jsScopeData we
369 // call Window::destroyWindow(), which makes the JS object unusable
370 // (trying to unregister something on it will throw).
371 // The registry entry goes first so lookups never return a window being torn down.
372 m_jsWindowRegistrationHandle.reset();
373 m_subWindowCloseRegistrationHandle.reset();
374}
375
376void QOhosWindowProxy::removeStartingWindow()
377{
378 QOhosJsThreadGateway::invokeAndWaitForContinue(
379 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
380 if (m_jsScopeData->isWindowClosing()) {
381 taskPromise();
382 return;
383 }
384 auto optQUiAbilityPeer
385 = QtOhos::QUiAbilityPeer::tryCastFromQAbilityPeerOrNull(m_jsScopeData->qAbilityPeer);
386 if (!optQUiAbilityPeer) {
387 taskPromise();
388 return;
389 }
390 auto promise = optQUiAbilityPeer->windowStage().evalToPromiseOrRejectOnThrow(
391 "removeStartingWindow()");
392 promise
393 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
394 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
395 },
396 Q_FUNC_INFO);
397}
398
400 const QPoint &point, std::optional<QOhosDisplayInfo::JsDisplayId> optMoveToTargetDisplay)
401{
402 auto displayIdValue = optMoveToTargetDisplay.value_or(QOhosDisplayInfo::JsDisplayId(-1)).value();
403 qOhosPrintfDebug("%s: %d,%d,%f", Q_FUNC_INFO, point.x(), point.y(), displayIdValue);
404
405 QOhosJsThreadGateway::invokeAndWaitForContinue(
406 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
407 if (m_jsScopeData->isWindowClosing()) {
408 taskPromise();
409 return;
410 }
411
412 const auto primaryJsDisplayId = QOhosDisplayInfo::JsDisplayId(0);
413
414 auto targetDisplayId = optMoveToTargetDisplay.has_value()
415 ? optMoveToTargetDisplay.value()
416 : getWindowProperties().displayId.value_or(primaryJsDisplayId);
417
418 auto optDisplayInfo = qTransform(
419 QOhosDisplayInfo::tryGetDisplayById(jsState, targetDisplayId),
420 [&](auto displayObject) {
421 return QOhosDisplayInfo::makeFromOhosDisplayObject(jsState, displayObject);
422 });
423
424 auto optIsDisplayMainOrExtended = qTransform(
425 optDisplayInfo,
426 [](const QOhosDisplayInfo &displayInfo) {
427 return displayInfo.isDisplayMainOrExtended();
428 });
429
430 bool isDisplayMainOrExtended;
431 if (optIsDisplayMainOrExtended.has_value()) {
432 isDisplayMainOrExtended = optIsDisplayMainOrExtended.value();
433 } else {
434 qOhosPrintfWarning(
435 "%s: no display source mode detected. Assumming main/extended screen", Q_FUNC_INFO);
436 isDisplayMainOrExtended = true;
437 }
438
439 QNapi::Promise promise;
440 if (!isDisplayMainOrExtended) {
441 auto optDisplayOffset = qAndThen(
442 optDisplayInfo,
443 [](const QOhosDisplayInfo &displayInfo) {
444 return displayInfo.topLeftOffsetPixels;
445 });
446
447 const QPoint defaultDisplayOffset(0, 0);
448 auto targetCoordinates = point - optDisplayOffset.value_or(defaultDisplayOffset);
449
450 if (!optMoveToTargetDisplay.has_value())
451 qOhosPrintfWarning("%s: trying to move window to not valid target display", Q_FUNC_INFO);
452
453 auto moveConfigurationObject = toNapiObject(
454 jsState.env(),
455 MoveConfiguration {
456 .displayId = optMoveToTargetDisplay,
457 });
458
459 promise = m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
460 "moveWindowToGlobal(*)", {targetCoordinates.x(), targetCoordinates.y(), moveConfigurationObject});
461 } else {
462 promise = m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
463 "moveWindowToGlobalDisplay(*)", {point.x(), point.y()});
464 }
465
466 promise
467 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
468 .onFinally(std::move(taskPromise));
469 });
470}
471
472void QOhosWindowProxy::setSize(const QSize &size)
473{
474 qOhosPrintfDebug("%s: %d,%d", Q_FUNC_INFO, size.width(), size.height());
475
476 QOhosJsThreadGateway::invokeAndWaitForContinue(
477 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
478 if (m_jsScopeData->isWindowClosing()) {
479 taskPromise();
480 return;
481 }
482
483 const auto currentSize = getWindowPropertiesFromJsWindow(
484 m_jsScopeData->jsWindowRef->jsObject()).windowRect.size();
485 if (currentSize == size) {
486 taskPromise();
487 return;
488 }
489
490 auto promise = m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
491 "resizeAsync(*)", {size.width(), size.height()});
492 promise
493 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
494 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
495 },
496 Q_FUNC_INFO);
497}
498
499void QOhosWindowProxy::setWindowBackgroundColor(const QColor &color)
500{
501 qCDebug(QtForOhos) << Q_FUNC_INFO << color;
502
503 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
504 if (m_jsScopeData->isWindowClosing())
505 return;
506 m_jsScopeData->jsWindowRef->eval("setWindowBackgroundColor(*)", {color.name(QColor::HexArgb).toStdString()});
507 },
508 Q_FUNC_INFO);
509}
510
511void QOhosWindowProxy::setCustomCursor(const QImage &customCursorImage, const QPoint &hotSpot)
512{
513 const auto maxOhosCustomCursorSize = QSize(256, 256);
514 const auto customCursorSize = customCursorImage.size();
515 if (customCursorSize.width() > maxOhosCustomCursorSize.width()
516 || customCursorSize.height() > maxOhosCustomCursorSize.height()) {
517 qOhosPrintfError(
518 "%s: can't set %dx%d custom cursor, OHOS max custom cursor size is %dx%d",
519 Q_FUNC_INFO, customCursorSize.width(), customCursorSize.height(),
520 maxOhosCustomCursorSize.width(), maxOhosCustomCursorSize.height());
521 return;
522 }
523
524 auto convertedImage = customCursorImage.convertToFormat(QImage::Format_RGBA8888);
525 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
526 if (m_jsScopeData->isWindowClosing()) {
527 taskPromise();
528 return;
529 }
530 auto windowId = m_jsScopeData->jsWindowRef->jsObject().get<QNapi::Number>("getWindowProperties().id");
531
532 auto jsCursor = QNapi::makeObject(
533 jsState.env(),
534 {
535 {"pixelMap", makeOhosNapiPixelMapFromQImage(jsState, convertedImage)},
536 {"focusX", hotSpot.x()},
537 {"focusY", hotSpot.y()},
538 });
539
540 auto jsCursorConfig = QNapi::makeObject(
541 jsState.env(),
542 {
543 {"followSystem", false},
544 });
545
546 jsState.evalToPromiseOrRejectOnThrow(
547 "@ohos.multimodalInput.pointer.setCustomCursor(*)", {windowId, jsCursor, jsCursorConfig})
548 .onCatch(QtOhos::makeErrorLoggingJsCallback("setCustomCursor()"))
549 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
550 },
551 Q_FUNC_INFO);
552}
553
554void QOhosWindowProxy::setPointerStyleSync(const QCursor &cursor)
555{
556 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &jsState) {
557 if (m_jsScopeData->isWindowClosing())
558 return;
559 auto windowId = m_jsScopeData->jsWindowRef->jsObject().get<QNapi::Number>("getWindowProperties().id");
560
561 jsState.eval(
562 "@ohos.multimodalInput.pointer.setPointerStyleSync(*)",
563 {windowId, jsState.mapOhosEnumToJs(convertToOhosCursor(cursor.shape()))});
564 },
565 Q_FUNC_INFO);
566}
567
569{
570 return QOhosJsThreadGateway::eval(
571 [&](QOhosJsState &) {
572 if (m_jsScopeData->isWindowClosing())
573 return QArkUi::WindowProperties {};
574 return getWindowPropertiesFromJsWindow(m_jsScopeData->jsWindowRef->jsObject());
575 },
576 Q_FUNC_INFO);
577}
578
579void QOhosWindowProxy::setWindowCallbackReceiver(std::unique_ptr<WindowCallbacks> callbackReceiver)
580{
581 auto sharedWindowCallbackReceiver = std::shared_ptr<WindowCallbacks>(std::move(callbackReceiver));
582
583 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
584 m_jsScopeData->windowCallbackReceiver = QtOhos::moveToSharedPtr(WindowCallbacks {
585 .onWindowEvent = makeQtThreadWindowCallbackDelegate(&WindowCallbacks::onWindowEvent, sharedWindowCallbackReceiver),
586 .onWindowStatusChange = makeQtThreadWindowCallbackDelegate(&WindowCallbacks::onWindowStatusChange, sharedWindowCallbackReceiver),
587 .onWindowVisibilityChange = makeQtThreadWindowCallbackDelegate(&WindowCallbacks::onWindowVisibilityChange, sharedWindowCallbackReceiver),
588 .onTouchOutside = makeQtThreadWindowCallbackDelegate(&WindowCallbacks::onTouchOutside, sharedWindowCallbackReceiver),
589 .onAvoidAreaChange = makeQtThreadWindowCallbackDelegate(&WindowCallbacks::onAvoidAreaChange, sharedWindowCallbackReceiver),
590 .onWindowRectChange = makeCompressingQtThreadWindowCallbackDelegate(&WindowCallbacks::onWindowRectChange, sharedWindowCallbackReceiver),
591 .onWindowRectChangeInGlobalDisplay = makeCompressingQtThreadWindowCallbackDelegate(&WindowCallbacks::onWindowRectChangeInGlobalDisplay, sharedWindowCallbackReceiver),
592 .onWindowDisplayIdChange = makeQtThreadWindowCallbackDelegate(&WindowCallbacks::onWindowDisplayIdChange, sharedWindowCallbackReceiver),
593 });
594 },
595 Q_FUNC_INFO);
596
597 m_qtWindowCallbacksReceiverHandle = sharedWindowCallbackReceiver;
598}
599
601 QObject *contextObject, QOhosConsumer<std::vector<NonClientAreaMouseEvent>> mouseEventBatchConsumer)
602{
603 auto qtConsumer = QtOhos::moveToSharedPtr(std::move(mouseEventBatchConsumer));
604 auto weakQtConsumer = QtOhos::makeWeakPtr(qtConsumer);
605
606 auto jsConsumer = makeQtOhosSimpleBatchingQtRequestsHandler<NonClientAreaMouseEvent>(
607 QtOhos::QObjectThreadSafeRef(contextObject),
608 [weakQtConsumer](std::vector<NonClientAreaMouseEvent> &&batch) {
609 auto qtConsumer = weakQtConsumer.lock();
610 if (qtConsumer)
611 (*qtConsumer)(std::move(batch));
612 });
613
614 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
615 m_jsScopeData->nonClientAreaEventsDispatcher->mouseEventsConsumer = std::move(jsConsumer);
616 },
617 Q_FUNC_INFO);
618
619 m_qtNonClientAreaMouseWindowCallbackReceiverHandle = qtConsumer;
620}
621
623 QObject *contextObject, QOhosConsumer<std::vector<NonClientAreaTouchEvent>> touchEventBatchConsumer)
624{
625 auto qtConsumer = QtOhos::moveToSharedPtr(std::move(touchEventBatchConsumer));
626 auto weakQtConsumer = QtOhos::makeWeakPtr(qtConsumer);
627
628 auto jsConsumer = makeQtOhosSimpleBatchingQtRequestsHandler<NonClientAreaTouchEvent>(
629 QtOhos::QObjectThreadSafeRef(contextObject),
630 [weakQtConsumer](std::vector<NonClientAreaTouchEvent> &&batch) {
631 auto qtConsumer = weakQtConsumer.lock();
632 if (qtConsumer)
633 (*qtConsumer)(std::move(batch));
634 });
635
636 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
637 m_jsScopeData->nonClientAreaEventsDispatcher->touchEventsConsumer = std::move(jsConsumer);
638 },
639 Q_FUNC_INFO);
640
641 m_qtNonClientAreaTouchWindowCallbackReceiverHandle = qtConsumer;
642}
643
644bool QOhosWindowProxy::qtIsMainWindow() const
645{
646 return m_windowProxyType == WindowProxyType::MainWindow;
647}
648
649void QOhosWindowProxy::raiseToAppTop()
650{
651 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
652 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
653 if (m_jsScopeData->isWindowClosing()) {
654 taskPromise();
655 return;
656 }
657 auto promise = m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("raiseToAppTop()");
658 promise
659 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
660 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
661 },
662 Q_FUNC_INFO);
663}
664
665void QOhosWindowProxy::showWindow(const ShowWindowOptions &options)
666{
667 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
668 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
669 if (m_jsScopeData->isWindowClosing()) {
670 taskPromise();
671 return;
672 }
673
674 std::vector<std::pair<std::string, QNapi::ValueWrapper>> jsOptionsProps;
675
676 if (options.focusOnShow.has_value())
677 jsOptionsProps.emplace_back("focusOnShow", options.focusOnShow.value());
678
679 std::vector<QNapi::ValueWrapper> showWindowArgs;
680 constexpr bool brokenHandlingOfEmptyOptionsParamInOhos = true;
681 if (!(jsOptionsProps.empty() && brokenHandlingOfEmptyOptionsParamInOhos))
682 showWindowArgs.push_back(QNapi::makeObject(jsState.env(), jsOptionsProps));
683
684 auto promise = m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("showWindow(*)", showWindowArgs);
685 promise
686 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
687 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
688 },
689 Q_FUNC_INFO);
690}
691
692void QOhosWindowProxy::recover()
693{
694 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
695 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
696 if (m_jsScopeData->isWindowClosing()) {
697 taskPromise();
698 return;
699 }
700
701 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("recover()")
702 .onCatch(QtOhos::makeErrorLoggingJsCallback("recover()"))
703 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
704 },
705 Q_FUNC_INFO);
706}
707
708void QOhosWindowProxy::restore()
709{
710 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
711 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
712 if (m_jsScopeData->isWindowClosing()) {
713 taskPromise();
714 return;
715 }
716 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("restore()")
717 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
718 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
719 },
720 Q_FUNC_INFO);
721}
722
723void QOhosWindowProxy::minimize()
724{
725 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
726 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
727 if (m_jsScopeData->isWindowClosing()) {
728 taskPromise();
729 return;
730 }
731 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("minimize()")
732 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
733 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
734 },
735 Q_FUNC_INFO);
736}
737
738void QOhosWindowProxy::maximize(MaximizePresentation maximizePresentation)
739{
740 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
741
742 if (!qtIsMainWindow()) {
743 qCWarning(QtForOhos(), "%s: Maximize is currently supported only on main windows", Q_FUNC_INFO);
744 return;
745 }
746
747 QOhosJsThreadGateway::invokeAndWaitForContinue(
748 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
749 if (m_jsScopeData->isWindowClosing()) {
750 taskPromise();
751 return;
752 }
753
754 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
755 "maximize(*)", {jsState.mapOhosEnumToJs(maximizePresentation)})
756 .onCatch(QtOhos::makeErrorLoggingJsCallback("maximize()"))
757 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
758 },
759 Q_FUNC_INFO);
760}
761
762void QOhosWindowProxy::setWindowLayoutFullScreen(bool isLayoutFullScreen)
763{
764 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, isLayoutFullScreen ? "true" : "false");
765 QOhosJsThreadGateway::invokeAndWaitForContinue(
766 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
767 if (m_jsScopeData->isWindowClosing()) {
768 taskPromise();
769 return;
770 }
771 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
772 "setWindowLayoutFullScreen(*)", {isLayoutFullScreen})
773 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowLayoutFullScreen()"))
774 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
775 },
776 Q_FUNC_INFO);
777}
778
779void QOhosWindowProxy::setWindowSystemBarEnable(const QStringList &names)
780{
781 qCDebug(QtForOhos) << Q_FUNC_INFO << names;
782 QOhosJsThreadGateway::invokeAndWaitForContinue(
783 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
784 if (m_jsScopeData->isWindowClosing()) {
785 taskPromise();
786 return;
787 }
788 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
789 "setWindowSystemBarEnable(*)",
790 {QNapi::makeArray(jsState.env(), names, std::mem_fn(&QString::toStdString))})
791 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowSystemBarEnable()"))
792 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
793 },
794 Q_FUNC_INFO);
795}
796
797void QOhosWindowProxy::showAbility()
798{
799 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
800
801 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
802 if (m_jsScopeData->isWindowClosing()) {
803 taskPromise();
804 return;
805 }
806
807 m_jsScopeData->qAbilityPeer->qAbility().evalToPromiseOrRejectOnThrow("context.showAbility()")
808 .onCatch(QtOhos::makeErrorLoggingJsCallback("showAbility()"))
809 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
810 },
811 Q_FUNC_INFO);
812}
813
814bool QOhosWindowProxy::tryHideAbility()
815{
816 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
817
818 return QOhosJsThreadGateway::evalWithPromise<bool>([&](QOhosJsState &, QOhosTaskPromise<bool> evalPromise) {
819 if (m_jsScopeData->isWindowClosing()) {
820 evalPromise(false);
821 return;
822 }
823
824 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
825 m_jsScopeData->qAbilityPeer->qAbility().evalToPromiseOrRejectOnThrow("context.hideAbility()")
826 .onThen(
827 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &) {
828 thenPromise(true);
829 })
830 .onCatch(
831 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
832 QtOhos::logJsCallbackError(cbInfo, "got error from hideAbility()");
833 catchPromise(false);
834 });
835 },
836 Q_FUNC_INFO);
837}
838
839bool QOhosWindowProxy::getImmersiveModeEnabledState()
840{
841 return QOhosJsThreadGateway::eval(
842 [&](QOhosJsState &) {
843 if (m_jsScopeData->isWindowClosing())
844 return false;
845 return m_jsScopeData->jsWindowRef->eval<QNapi::Boolean>("getImmersiveModeEnabledState()").Value();
846 },
847 Q_FUNC_INFO);
848}
849
850void QOhosWindowProxy::setWindowPrivacyMode(bool privacyMode)
851{
852 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, privacyMode ? "true" : "false");
853
854 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
855 if (m_jsScopeData->isWindowClosing()) {
856 taskPromise();
857 return;
858 }
859
860 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowPrivacyMode(*)", {privacyMode})
861 .onCatch(QtOhos::makeErrorLoggingJsCallback("setPrivacyMode()"))
862 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
863 },
864 Q_FUNC_INFO);
865}
866
867void QOhosWindowProxy::setWindowFocusable(bool focusable)
868{
869 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, focusable ? "true" : "false");
870 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
871 if (m_jsScopeData->isWindowClosing()) {
872 taskPromise();
873 return;
874 }
875
876 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowFocusable(*)", {focusable})
877 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowFocusable()"))
878 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
879 },
880 Q_FUNC_INFO);
881}
882
883void QOhosWindowProxy::setWindowTouchable(bool touchable)
884{
885 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, touchable ? "true" : "false");
886 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
887 if (m_jsScopeData->isWindowClosing()) {
888 taskPromise();
889 return;
890 }
891
892 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowTouchable(*)", {touchable})
893 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowTouchable()"))
894 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
895 },
896 Q_FUNC_INFO);
897}
898
899void QOhosWindowProxy::setWindowLimits(const QSize &minSize, const QSize &maxSize)
900{
901 qCDebug(
902 QtForOhos, "%s: (%d x %d)-(%d x %d)", Q_FUNC_INFO, minSize.width(), minSize.height(),
903 maxSize.width(), maxSize.height());
904 QOhosJsThreadGateway::invokeAndWaitForContinue(
905 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
906 if (m_jsScopeData->isWindowClosing()) {
907 taskPromise();
908 return;
909 }
910 auto windowLimits = QNapi::makeObject(
911 jsState.env(),
912 {
913 {"minWidth", minSize.width()},
914 {"minHeight", minSize.height()},
915 {"maxWidth", maxSize.width()},
916 {"maxHeight", maxSize.height()},
917 });
918
919 std::vector<QNapi::ValueWrapper> setWindowLimitsArgs = {windowLimits};
920 if (QOhosDeviceInfo::is2in1()) {
921 constexpr bool isForcible = true;
922 setWindowLimitsArgs.push_back(isForcible);
923 }
924 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
925 "setWindowLimits(*)", setWindowLimitsArgs)
926 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowLimits()"))
927 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
928 },
929 Q_FUNC_INFO);
930}
931
932QOhosWindowProxy::WindowLimits QOhosWindowProxy::getWindowLimits() const
933{
934 qCDebug(QtForOhos, "%s", Q_FUNC_INFO);
935 return QOhosJsThreadGateway::eval(
936 [&](QOhosJsState &) {
937 if (m_jsScopeData->isWindowClosing())
938 return WindowLimits {};
939 auto windowLimitsObject = m_jsScopeData->jsWindowRef->eval<QNapi::Object>("getWindowLimits()");
940 return WindowLimits {
941 .minWidth = getOptionalNumberPropAsOptionalDouble(windowLimitsObject, "minWidth"),
942 .minHeight = getOptionalNumberPropAsOptionalDouble(windowLimitsObject, "minHeight"),
943 .maxWidth = getOptionalNumberPropAsOptionalDouble(windowLimitsObject, "maxWidth"),
944 .maxHeight = getOptionalNumberPropAsOptionalDouble(windowLimitsObject, "maxHeight"),
945 };
946 },
947 Q_FUNC_INFO);
948}
949
950QOhosWindowProxy::AvoidArea QOhosWindowProxy::getWindowAvoidArea(AvoidAreaType avoidAreaType) const
951{
952 qCDebug(QtForOhos, "%s: %d", Q_FUNC_INFO, avoidAreaType);
953 return QOhosJsThreadGateway::eval(
954 [&](QOhosJsState &jsState) {
955 if (m_jsScopeData->isWindowClosing())
956 return AvoidArea {};
957 auto avoidAreaObject = m_jsScopeData->jsWindowRef->eval<QNapi::Object>(
958 "getWindowAvoidArea(*)", {jsState.mapOhosEnumToJs(avoidAreaType)});
959 return mapAvoidAreaFromJs(avoidAreaObject);
960 },
961 Q_FUNC_INFO);
962}
963
964void QOhosWindowProxy::setWindowMask(
965 const WindowMask &windowMask, const std::optional<QSize> &ohosMaskSizeOverride)
966{
968 return;
969
970 auto ohosMaskSize = ohosMaskSizeOverride.has_value()
971 ? ohosMaskSizeOverride.value()
972 : getWindowProperties().windowRect.size();
973
974 if (ohosMaskSize.isEmpty()) {
975 const auto *maskSrcSizeMsg = ohosMaskSizeOverride.has_value()
976 ? "overridden mask source"
977 : "window";
978 if (ohosMaskSizeOverride.has_value()) {
979 qOhosPrintfError(
980 "%s failed - %s size is 0x0", maskSrcSizeMsg,
981 "QOhosWindowProxy::setWindowMask");
982 }
983 return;
984 }
985
986 QOhosJsThreadGateway::invokeAndWaitForContinue([&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
987 if (m_jsScopeData->isWindowClosing()) {
988 taskPromise();
989 return;
990 }
991 auto *env = jsState.env();
992
993 QNapi::Array maskRowsArray = QNapi::Array::New(env, ohosMaskSize.height());
994 const int defaultValue = windowMask.windowMaskRegion.isEmpty() ? 1 : 0;
995
996 for (int rowIndex = 0; rowIndex < ohosMaskSize.height(); ++rowIndex) {
997 auto arr = QNapi::Array::New(env, ohosMaskSize.width());
998 arr.fill(defaultValue);
999 maskRowsArray[rowIndex] = arr;
1000 }
1001
1002 auto valueToSet = QNapi::Number::New(env, 1);
1003 for (const auto &rect: windowMask.windowMaskRegion) {
1004 auto top = qBound(0, rect.top(), ohosMaskSize.height() - 1);
1005 auto bottom = qBound(0, rect.bottom(), ohosMaskSize.height() - 1);
1006 auto left = qBound(0, rect.left(), ohosMaskSize.width() - 1);
1007 auto right = qBound(0, rect.right(), ohosMaskSize.width() - 1);
1008
1009 for (auto rowIndex = top; rowIndex <= bottom; ++rowIndex) {
1010 auto row = maskRowsArray.Get(rowIndex).As<QNapi::Array>();
1011 for (auto columnIndex = left; columnIndex <= right; ++columnIndex)
1012 row[columnIndex] = valueToSet;
1013 }
1014 }
1015
1016 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowMask(*)", {maskRowsArray})
1017 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowMask()"))
1018 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1019 },
1020 Q_FUNC_INFO);
1021}
1022
1023void QOhosWindowProxy::setSubWindowModalDisabled()
1024{
1025 if (qtIsMainWindow())
1026 return;
1027
1028 QOhosJsThreadGateway::invokeAndWaitForContinue(
1029 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1030 if (m_jsScopeData->isWindowClosing()) {
1031 taskPromise();
1032 return;
1033 }
1034 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setSubWindowModal(*)", {false})
1035 .onCatch(QtOhos::makeErrorLoggingJsCallback("setSubWindowModal()"))
1036 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1037 },
1038 Q_FUNC_INFO);
1039}
1040
1041void QOhosWindowProxy::setSubWindowModalEnabled(ModalityType modalityType)
1042{
1043 if (qtIsMainWindow())
1044 return;
1045
1047 qOhosPrintfWarning(
1048 "%s: APPLICATION_MODALITY option can be used only on devices in the freeform window state - skipping",
1049 Q_FUNC_INFO);
1050 return;
1051 }
1052
1053 QOhosJsThreadGateway::invokeAndWaitForContinue(
1054 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
1055 if (m_jsScopeData->isWindowClosing()) {
1056 taskPromise();
1057 return;
1058 }
1059 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
1060 "setSubWindowModal(*)", {true, jsState.mapOhosEnumToJs(modalityType)})
1061 .onCatch(QtOhos::makeErrorLoggingJsCallback("setSubWindowModal()"))
1062 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1063 },
1064 Q_FUNC_INFO);
1065}
1066
1067void QOhosWindowProxy::setTitle(const QString &title)
1068{
1069 QOhosJsThreadGateway::invokeAndWaitForContinue(
1070 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1071 if (m_jsScopeData->isWindowClosing()) {
1072 taskPromise();
1073 return;
1074 }
1075
1076 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowTitle(*)", {title.toStdString()})
1077 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
1078 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1079 },
1080 Q_FUNC_INFO);
1081}
1082
1083void QOhosWindowProxy::setWindowTitleButtonVisible(bool maximizeVisible, bool minimizeVisible, bool closeVisible)
1084{
1085 qOhosPrintfDebug(
1086 "%s: isMaximizeVisible:%s, isMinimizeVisible:%s, isCloseVisible:%s",
1087 Q_FUNC_INFO, maximizeVisible ? "true" : "false", minimizeVisible ? "true": "false",
1088 closeVisible ? "true" : "false");
1089
1090 if (!qtIsMainWindow())
1091 return;
1092
1093 QOhosJsThreadGateway::runAndWait(
1094 [&](QOhosJsState &jsState) {
1095 if (m_jsScopeData->isWindowClosing())
1096 return;
1097
1098 constexpr auto capabilityNotSupportedErrorCode = 801;
1099 QtOhos::runIgnoringJsBusinessError(
1100 jsState, capabilityNotSupportedErrorCode, "setWindowTitleButtonVisible()",
1101 [&]() {
1102 m_jsScopeData->jsWindowRef->eval(
1103 "setWindowTitleButtonVisible(*)",
1104 {maximizeVisible, minimizeVisible, closeVisible});
1105 });
1106 },
1107 Q_FUNC_INFO);
1108}
1109
1110void QOhosWindowProxy::setWindowTopmost(bool topmost)
1111{
1112 if (!qtIsMainWindow())
1113 return;
1114
1116 qOhosPrintfWarning("%s: can be used only on 2-in-1 devices or tablets in PC mode - skipping", Q_FUNC_INFO);
1117 return;
1118 }
1119
1120 qOhosPrintfDebug("%s: topMost: %s", Q_FUNC_INFO, topmost ? "true" : "false");
1121
1122 QOhosJsThreadGateway::invokeAndWaitForContinue(
1123 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1124 if (m_jsScopeData->isWindowClosing()) {
1125 taskPromise();
1126 return;
1127 }
1128
1129 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowTopmost(*)", {topmost})
1130 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
1131 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1132 },
1133 Q_FUNC_INFO);
1134}
1135
1136void QOhosWindowProxy::setWindowDecorVisible(bool visible)
1137{
1138 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
1139 if (m_jsScopeData->isWindowClosing())
1140 return;
1141
1142 m_jsScopeData->jsWindowRef->eval("setWindowDecorVisible(*)", {visible});
1143 },
1144 Q_FUNC_INFO);
1145}
1146
1147void QOhosWindowProxy::setWindowTitleMoveEnabled(bool enabled)
1148{
1150 qOhosPrintfWarning("%s: can be used only on 2-in-1 devices or tablets in PC mode - skipping", Q_FUNC_INFO);
1151 return;
1152 }
1153
1154 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
1155 if (m_jsScopeData->isWindowClosing())
1156 return;
1157
1158 m_jsScopeData->jsWindowRef->eval("setWindowTitleMoveEnabled(*)", {enabled});
1159 },
1160 Q_FUNC_INFO);
1161}
1162
1163void QOhosWindowProxy::setWindowShadowRadius(double radius)
1164{
1166 qOhosPrintfWarning("%s: can be used only on 2-in-1 devices or tablets - skipping", Q_FUNC_INFO);
1167 return;
1168 }
1169
1170 if (qtIsMainWindow())
1171 return;
1172
1173 QOhosJsThreadGateway::runAndWait([&](QOhosJsState &) {
1174 m_jsScopeData->jsWindowRef->eval("setWindowShadowRadius(*)", {radius});
1175 },
1176 Q_FUNC_INFO);
1177}
1178
1179void QOhosWindowProxy::setWindowCornerRadius(double radius)
1180{
1181 if (qtIsMainWindow())
1182 return;
1183
1184 QOhosJsThreadGateway::invokeAndWaitForContinue(
1185 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1186 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowCornerRadius(*)", {radius})
1187 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
1188 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1189 },
1190 Q_FUNC_INFO);
1191}
1192
1193bool QOhosWindowProxy::isWindowRectAutoSave() const
1194{
1195 return QOhosJsThreadGateway::evalWithPromise<bool>(
1196 [&](QOhosJsState &, QOhosTaskPromise<bool> evalPromise) {
1197 if (m_jsScopeData->isWindowClosing()) {
1198 evalPromise(false);
1199 return;
1200 }
1201 auto optQUiAbilityPeer = QtOhos::QUiAbilityPeer::tryCastFromQAbilityPeerOrNull(m_jsScopeData->qAbilityPeer);
1202 if (!optQUiAbilityPeer) {
1203 evalPromise(false);
1204 return;
1205 }
1206
1207 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
1208 optQUiAbilityPeer->windowStage()
1209 .evalToPromiseOrRejectOnThrow("isWindowRectAutoSave()")
1210 .onThen(
1211 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
1212 bool windowRectAutoSaveEnabled = cbInfo.getFirstArg<QNapi::Boolean>(Q_FUNC_INFO);
1213 thenPromise(windowRectAutoSaveEnabled);
1214 })
1215 .onCatch(
1216 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
1217 QtOhos::logJsCallbackError(cbInfo, "isWindowRectAutoSave()");
1218 catchPromise(false);
1219 });
1220 },
1221 Q_FUNC_INFO);
1222}
1223
1224void QOhosWindowProxy::setFollowParentMultiScreenPolicy(bool enabled)
1225{
1226 if (qtIsMainWindow())
1227 return;
1228
1229 QOhosJsThreadGateway::invokeAndWaitForContinue(
1230 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1231 if (m_jsScopeData->isWindowClosing()) {
1232 taskPromise();
1233 return;
1234 }
1235 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setFollowParentMultiScreenPolicy(*)", {enabled})
1236 .onCatch(QtOhos::makeErrorLoggingJsCallback("setFollowParentMultiScreenPolicy()"))
1237 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1238 },
1239 Q_FUNC_INFO);
1240}
1241
1242void QOhosWindowProxy::setWindowKeepScreenOn(bool keepScreenOn)
1243{
1244 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, QtOhos::mapBoolToTrueFalseStr(keepScreenOn));
1245
1246 QOhosJsThreadGateway::invokeAndWaitForContinue(
1247 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1248 if (m_jsScopeData->isWindowClosing()) {
1249 taskPromise();
1250 return;
1251 }
1252
1253 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("setWindowKeepScreenOn(*)", {keepScreenOn})
1254 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowKeepScreenOn()"))
1255 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1256 },
1257 Q_FUNC_INFO);
1258}
1259
1260void QOhosWindowProxy::setSupportedWindowModes(const std::set<SupportWindowMode> &supportedWindowModes)
1261{
1262 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, mapEnumsToLogString(supportedWindowModes).c_str());
1263
1264 QOhosJsThreadGateway::invokeAndWaitForContinue(
1265 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
1266 if (m_jsScopeData->isWindowClosing()) {
1267 taskPromise();
1268 return;
1269 }
1270 auto qUiAbilityPeer = QtOhos::QUiAbilityPeer::tryCastFromQAbilityPeerOrNull(m_jsScopeData->qAbilityPeer);
1271 if (!qUiAbilityPeer) {
1272 taskPromise();
1273 return;
1274 }
1275
1276 auto jsSupportedWindowModes = QNapi::makeArray(
1277 jsState.env(), supportedWindowModes,
1278 [&](auto mode) {
1279 return jsState.mapOhosEnumToJs(mode);
1280 });
1281
1282 qUiAbilityPeer->windowStage().evalToPromiseOrRejectOnThrow("setSupportedWindowModes(*)", {jsSupportedWindowModes})
1283 .onCatch(QtOhos::makeErrorLoggingJsCallback("setSupportedWindowModes()"))
1284 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1285 },
1286 Q_FUNC_INFO);
1287}
1288
1289void QOhosWindowProxy::setWindowRectAutoSave(bool enabled)
1290{
1291 constexpr bool isSaveBySpecifiedFlag = true;
1292
1293 QOhosJsThreadGateway::invokeAndWaitForContinue(
1294 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1295 if (m_jsScopeData->isWindowClosing()) {
1296 taskPromise();
1297 return;
1298 }
1299 auto optQUiAbilityPeer = QtOhos::QUiAbilityPeer::tryCastFromQAbilityPeerOrNull(m_jsScopeData->qAbilityPeer);
1300 if (!optQUiAbilityPeer) {
1301 taskPromise();
1302 return;
1303 }
1304
1305 optQUiAbilityPeer->windowStage()
1306 .evalToPromiseOrRejectOnThrow("setWindowRectAutoSave(*)", {enabled, isSaveBySpecifiedFlag})
1307 .onCatch(QtOhos::makeErrorLoggingJsCallback("setWindowRectAutoSave()"))
1308 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1309 },
1310 Q_FUNC_INFO);
1311}
1312
1313void QOhosWindowProxy::setSubWindowCloseHandler(
1314 std::function<void()> handler, bool handlerReturnValue)
1315{
1316 m_subWindowCloseRegistrationHandle =
1317 registerSubWindowCloseHandler(std::move(handler), handlerReturnValue);
1318}
1319
1320void QOhosWindowProxy::resetSubWindowCloseHandler()
1321{
1322 m_subWindowCloseRegistrationHandle.reset();
1323}
1324
1325std::shared_ptr<void> QOhosWindowProxy::registerSubWindowCloseHandler(
1326 std::function<void()> handler, bool handlerReturnValue)
1327{
1328 auto sharedHandler = QtOhos::moveToSharedPtr(std::move(handler));
1329 auto jsWindowRegistrationHandle = QOhosJsThreadGateway::eval(
1330 [&](QOhosJsState &jsState) {
1331 return QtOhos::makeProxyWithJsThreadDeleter(
1332 m_jsScopeData->registerSubWindowCloseHandler(
1333 jsState,
1334 [weakHandler = QtOhos::makeWeakPtr(sharedHandler), handlerReturnValue]() {
1335 QtOhos::invokeInQtThread(
1336 [weakHandler]() {
1337 auto sharedHandler = weakHandler.lock();
1338 if (sharedHandler)
1339 (*sharedHandler)();
1340 });
1341 return handlerReturnValue;
1342 }));
1343 },
1344 Q_FUNC_INFO);
1345
1346 return QtOhos::moveToSharedPtr(
1347 std::make_tuple(sharedHandler, jsWindowRegistrationHandle));
1348}
1349
1350std::shared_ptr<QOhosWindowProxy>
1352{
1353 return std::shared_ptr<QOhosWindowProxy>(
1354 new QOhosWindowProxy(
1355 [&](QtOhos::JsState &jsState, QOhosConsumer<QtOhos::JsState &, QOhosWindowProxyData> windowProxyDataConsumer) {
1356 makeWindowProxyDataForExistingMainWindowInJsThread(jsState, createInfo, std::move(windowProxyDataConsumer));
1357 }));
1358}
1359
1360std::shared_ptr<QOhosWindowProxy>
1361QOhosWindowProxy::createFloatWindow(const FloatWindowCreateInfo &createInfo)
1362{
1363 return std::shared_ptr<QOhosWindowProxy>(
1364 new QOhosWindowProxy(
1365 [&](QtOhos::JsState &jsState, QOhosConsumer<QtOhos::JsState &, QOhosWindowProxyData> windowProxyDataConsumer) {
1366 makeWindowProxyDataForFloatWindowInJsThread(jsState, createInfo, std::move(windowProxyDataConsumer));
1367 }));
1368}
1369
1370std::shared_ptr<QOhosWindowProxy>
1371QOhosWindowProxy::createMainWindow(const MainWindowCreateInfo &createInfo)
1372{
1373 return std::shared_ptr<QOhosWindowProxy>(
1374 new QOhosWindowProxy(
1375 [&](QtOhos::JsState &jsState, QOhosConsumer<QtOhos::JsState &, QOhosWindowProxyData> windowProxyDataConsumer) {
1376 makeWindowProxyDataForMainWindowInJsThread(jsState, createInfo, std::move(windowProxyDataConsumer));
1377 }));
1378}
1379
1380std::shared_ptr<QXComponentNode> QOhosWindowProxy::nodeXComponent() const
1381{
1382 return m_nodeXComponent;
1383}
1384
1385std::string QOhosWindowProxy::qAbilityInstanceId() const
1386{
1387 return m_qAbilityInstanceId;
1388}
1389
1390std::shared_ptr<QOhosWindowProxy>
1391QOhosWindowProxy::createSubWindow(const SubWindowCreateInfo &createInfo)
1392{
1393 return std::shared_ptr<QOhosWindowProxy>(
1394 new QOhosWindowProxy(
1395 [&](QtOhos::JsState &jsState, QOhosConsumer<QtOhos::JsState &, QOhosWindowProxyData> windowProxyDataConsumer) {
1396 // HACK - calling createSubWindow from window may throw while the context is termination
1397 // This is only a problem because we currenlty do not properly handle main window closing
1398 // Remove this hacky branch after QTFOROH-1080 issues are resolved.
1399 if (m_jsScopeData->isWindowClosing()) {
1400 makeWindowProxyDataForSubWindowInJsThread(
1401 jsState, createInfo, std::move(windowProxyDataConsumer));
1402 } else {
1403 makeWindowProxyDataForSubWindowInJsThread(
1404 jsState, m_jsScopeData->jsWindowRef->jsObject(), createInfo,
1405 std::move(windowProxyDataConsumer));
1406 }
1407 }));
1408}
1409
1410QOhosWindowProxy::JsScopeData::JsScopeData() = default;
1411
1412QOhosWindowProxy::JsScopeData::JsScopeData(
1413 WindowProxyType windowProxyType, QNapi::Reference<QNapi::Object> jsWindow,
1414 std::shared_ptr<void> optKeepAliveData,
1415 std::shared_ptr<QtOhos::QAbilityPeer> qAbilityPeer,
1416 QtOhos::QObjectThreadSafeRef owningQWindowRef)
1417 : windowProxyType(windowProxyType)
1418 , windowCallbackReceiver(nullptr)
1419 , windowDestroyedFromSystem(false)
1420 , optKeepAliveData(optKeepAliveData)
1421 , qAbilityPeer(qAbilityPeer)
1422 , nonClientAreaEventsDispatcher(std::make_shared<NonClientAreaEventsDispatcher>())
1423 , m_windowFrameMouseFilterHandle(
1424 QArkUi::registerMouseEventsConsumer(
1425 getWindowPropertiesFromJsWindow(jsWindow.Value()).id,
1426 [dispatcher = nonClientAreaEventsDispatcher](const QArkUi::MouseEvent &event) {
1427 dispatcher->onMouseEventFromArkUi(event);
1428 }))
1429 , m_windowFrameTouchFilterHandle(
1430 QArkUi::registerTouchEventsConsumer(
1431 getWindowPropertiesFromJsWindow(jsWindow.Value()).id,
1432 [dispatcher = nonClientAreaEventsDispatcher](const QArkUi::TouchEvent &event) {
1433 dispatcher->onTouchEventFromArkUi(event);
1434 }))
1435 , jsWindowRef(
1436 std::make_shared<QArkUi::JsWindowRef>(
1437 qAbilityPeer->instanceId(),
1438 getWindowPropertiesFromJsWindow(jsWindow.Value()).id,
1439 jsWindow.Value(),
1440 owningQWindowRef))
1441{
1442}
1443
1444QOhosWindowProxy::JsScopeData::~JsScopeData()
1445{
1446 if (jsWindowRef) {
1447 if (isWindowClosingFromSystem(jsWindowRef->jsObject(), windowProxyType, qAbilityPeer)) {
1448 windowDestroyedFromSystem = true;
1449 return;
1450 }
1451
1452 QtOhos::JsWindowsTracker::tagWindowAsClosing(jsWindowRef->jsObject(), "QOhosWindowProxy::JsScopeData destructor");
1453
1454 if (windowProxyType == WindowProxyType::MainWindow) {
1455 // NOTE - Set the windowDestroyedFromSystem flag here early
1456 // to avoid callbacks being invoked directly as a result of
1457 // calling terminate
1458 windowDestroyedFromSystem = true;
1459 qOhosPrintfWarning(
1460 "Attempting to terminate qAbility with instance id: %s",
1461 jsWindowRef->owningQAbilityInstanceId().c_str());
1462 qAbilityPeer->qAbility().eval("context.terminateSelf()");
1463 } else if (!windowDestroyedFromSystem) {
1464 // FIXME - destroyWindow usually does and returns nothing
1465 // once the actual implementation is provided wait for the proomise that this function should return
1466 jsWindowRef->eval("destroyWindow()");
1467 }
1468 }
1469}
1470
1471std::shared_ptr<void> QOhosWindowProxy::JsScopeData::registerEventListener(
1472 const std::string &eventName,
1473 void (QOhosWindowProxy::JsScopeData::*handleFunction)(const QtOhos::CallbackInfo &),
1474 QFlags<EventHandlerFlagBits> eventHandlerFlags)
1475{
1476
1477 std::weak_ptr<JsScopeData> weakSelf = shared_from_this();
1478 bool ignoreWhenAbilityIsTerminating = !eventHandlerFlags.testFlag(EventHandlerFlagBits::allowCallWhenAbilityIsTerminating);
1479
1480 return registerQOhosOnOffMethodsBasedEventHandler(
1481 jsWindowRef->jsObject(), eventName,
1482 [weakSelf, handleFunction, eventName, ignoreWhenAbilityIsTerminating](const QtOhos::CallbackInfo &cbInfo) {
1483 auto self = weakSelf.lock();
1484 if (Q_UNLIKELY(!self)) {
1485 qOhosPrintfWarning(
1486 "callback '%s' called for destroyed QOhosWindowProxy::JsScopeData, ignoring",
1487 eventName.c_str());
1488 return;
1489 }
1490
1491 if (self->isWindowClosing() && ignoreWhenAbilityIsTerminating) {
1492 qOhosPrintfError(
1493 "QOhosWindowProxy: Received callback for event '%s' during termination of the related QAbility.",
1494 eventName.c_str());
1495 return;
1496 }
1497
1498 if (Q_UNLIKELY(self->windowDestroyedFromSystem)) {
1499 qOhosPrintfError(
1500 "QOhosWindowProxy: Received callback for event '%s' after WINDOW_DESTROYED",
1501 eventName.c_str());
1502 return;
1503 }
1504
1505 ((*self).*handleFunction)(cbInfo);
1506 },
1507 {
1508 .optEventSourceAliveCheckFunc = {},
1509 .extraOnArg = {},
1510 .extraOffArg = {},
1511 .optOnCallExceptionHandler = [&](const Napi::Error &error) {
1512 constexpr std::uint32_t capabilityNotSupportedErrorCode = 801;
1513 constexpr std::uint32_t windowStateIsAbnormalErrorCode = 1300002;
1514
1515 const QSet<std::uint32_t> ignorableErrorCodes = {
1516 capabilityNotSupportedErrorCode,
1517 windowStateIsAbnormalErrorCode,
1518 };
1519
1520 auto errorCode = QtOhos::tryGetCodeFromJsBusinessError(error);
1521
1522 auto ignorableError =
1523 eventHandlerFlags.testFlag(EventHandlerFlagBits::allowEventHandlerRegistrationFailure)
1524 && errorCode.has_value()
1525 && ignorableErrorCodes.contains(errorCode.value());
1526
1527 if (!ignorableError)
1528 throw;
1529
1530 qOhosPrintfWarning(
1531 "%s: Ignored error %u while registering for window event '%s'",
1532 Q_FUNC_INFO, errorCode.value(), eventName.c_str());
1533 },
1534 });
1535}
1536
1537std::shared_ptr<void> QOhosWindowProxy::JsScopeData::registerSubWindowCloseHandler(
1538 QOhosJsState &, std::function<bool()> handler)
1539{
1540 auto weakSelf = QtOhos::makeWeakPtr(shared_from_this());
1541 return registerQOhosOnOffMethodsBasedEventHandler(
1542 jsWindowRef->jsObject(), "subWindowClose",
1543 [weakSelf, handler = std::move(handler)](const QtOhos::CallbackInfo &cbInfo) {
1544 bool deferClose = handler();
1545 auto self = weakSelf.lock();
1546 if (self && !deferClose)
1547 QtOhos::JsWindowsTracker::tagWindowAsClosing(self->jsWindowRef->jsObject(), "subWindowClose => false");
1548 return QNapi::Boolean::New(cbInfo.Env(), deferClose);
1549 });
1550}
1551
1552void QOhosWindowProxy::JsScopeData::handleWindowEventCallback(const QtOhos::CallbackInfo &cbInfo)
1553{
1554 auto eventType = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
1555 // NOTE - All windowEvents should be handled by qt but currently
1556 // some are not exposed as a part of public api.
1557 WindowEvent event;
1558 try {
1559 event.type = cbInfo.jsState().mapOhosEnumFromJs<WindowEventType>(eventType);
1560 } catch (const Napi::Error &err) {
1561 qOhosPrintfError(
1562 "Error converting WindowEventType to known value: %s. Event will be ignored.", err.what());
1563 return;
1564 }
1565
1566 if (isWindowClosing() && event.type != WindowEventType::WINDOW_DESTROYED) {
1567 qOhosPrintfError(
1568 "Received WindowEvent for window when it's closing. WindowEventType: %d",
1569 event.type);
1570 return;
1571 }
1572
1573 onWindowEvent(cbInfo.jsState(), event);
1574}
1575
1576void QOhosWindowProxy::JsScopeData::handleWindowStatusCallback(const QtOhos::CallbackInfo &cbInfo)
1577{
1578 auto windowStatusType = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
1579 if (windowCallbackReceiver != nullptr) {
1580 windowCallbackReceiver->onWindowStatusChange(
1581 WindowStatus {
1582 .type = cbInfo.jsState().mapOhosEnumFromJs<WindowStatusType>(windowStatusType),
1583 });
1584 }
1585}
1586
1587void QOhosWindowProxy::JsScopeData::handleWindowVisibilityCallback(const QtOhos::CallbackInfo &cbInfo)
1588{
1589 auto windowVisibility = cbInfo.getFirstArg<QNapi::Boolean>(Q_FUNC_INFO);
1590 if (windowCallbackReceiver != nullptr)
1591 windowCallbackReceiver->onWindowVisibilityChange(windowVisibility);
1592}
1593
1594void QOhosWindowProxy::JsScopeData::handleWindowTouchOutsideCallback(const QtOhos::CallbackInfo &)
1595{
1596 if (windowCallbackReceiver != nullptr)
1597 windowCallbackReceiver->onTouchOutside();
1598}
1599
1600void QOhosWindowProxy::JsScopeData::handleAvoidAreaChangeCallback(const QtOhos::CallbackInfo &cbInfo)
1601{
1602 if (windowCallbackReceiver != nullptr) {
1603 auto callbackArg = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1604 windowCallbackReceiver->onAvoidAreaChange(
1605 cbInfo.jsState().mapOhosEnumFromJs<AvoidAreaType>(callbackArg.get<QNapi::Number>("type")),
1606 mapAvoidAreaFromJs(callbackArg.get<QNapi::Object>("area")));
1607 }
1608}
1609
1610void QOhosWindowProxy::JsScopeData::handleWindowRectChangeCallback(const QtOhos::CallbackInfo &cbInfo)
1611{
1612 auto rectChangeOptionsObjectArg = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1613 auto rectChangeOptions = RectChangeOptions {
1614 .rect = ohosWindowRectToQRect(rectChangeOptionsObjectArg.get<QNapi::Object>("rect")),
1615 .reason = cbInfo.jsState().mapOhosEnumFromJs<RectChangeReason>(rectChangeOptionsObjectArg.get<QNapi::Number>("reason")),
1616 };
1617
1618 if (windowCallbackReceiver != nullptr)
1619 windowCallbackReceiver->onWindowRectChange(rectChangeOptions);
1620}
1621
1622void QOhosWindowProxy::JsScopeData::handleWindowRectChangeInGlobalDisplayCallback(const QtOhos::CallbackInfo &cbInfo)
1623{
1624 auto rectChangeOptionsObjectArg = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1625 auto rectChangeOptions = RectChangeOptions {
1626 .rect = ohosWindowRectToQRect(rectChangeOptionsObjectArg.get<QNapi::Object>("rect")),
1627 .reason = cbInfo.jsState().mapOhosEnumFromJs<RectChangeReason>(rectChangeOptionsObjectArg.get<QNapi::Number>("reason")),
1628 };
1629
1630 if (windowCallbackReceiver != nullptr)
1631 windowCallbackReceiver->onWindowRectChangeInGlobalDisplay(rectChangeOptions);
1632}
1633
1634void QOhosWindowProxy::JsScopeData::handleWindowDisplayIdChangeCallback(const QtOhos::CallbackInfo &cbInfo)
1635{
1636 auto displayIdNumber = cbInfo.getFirstArg<QNapi::Number>(Q_FUNC_INFO);
1637 auto displayId = QOhosDisplayInfo::JsDisplayId(displayIdNumber);
1638
1639 if (windowCallbackReceiver != nullptr)
1640 windowCallbackReceiver->onWindowDisplayIdChange(displayId);
1641}
1642
1643void QOhosWindowProxy::JsScopeData::onWindowEvent(QtOhos::JsState &, const WindowEvent &windowEvent)
1644{
1645 if (windowEvent.type == WindowEventType::WINDOW_DESTROYED) {
1646 QtOhos::JsWindowsTracker::tagWindowAsClosing(jsWindowRef->jsObject(), "WINDOW_DESTROYED");
1647 windowDestroyedFromSystem = true;
1648 }
1649
1650 if (windowCallbackReceiver != nullptr)
1651 windowCallbackReceiver->onWindowEvent(windowEvent);
1652}
1653
1654bool QOhosWindowProxy::JsScopeData::isWindowClosing() const
1655{
1656 return isWindowClosingFromSystem(jsWindowRef->jsObject(), windowProxyType, qAbilityPeer);
1657}
1658
1659void QOhosWindowProxy::JsScopeData::NonClientAreaEventsDispatcher::onMouseEventFromArkUi(const QArkUi::MouseEvent &event) const
1660{
1661 if (mouseEventsConsumer == nullptr)
1662 return;
1663
1664 auto optAction = tryMapMouseEventActionToNonClientAreaEventType(event.action);
1665 if (!optAction.has_value())
1666 return;
1667
1668 auto optWindowProperties = QArkUi::tryGetWindowProperties(event.jsWindowId);
1669 if (!optWindowProperties.has_value()) {
1670 qOhosPrintfError(
1671 "%s: Failed to retrieve window properties for js window: %f. Ignoring event.",
1672 Q_FUNC_INFO, event.jsWindowId.value());
1673 return;
1674 }
1675
1676 const auto &windowProperties = optWindowProperties.value();
1677 if (!isPointInNonClientArea(event.displayPosition, windowProperties))
1678 return;
1679
1680 auto windowOrigin = windowProperties.windowRect.topLeft() + windowProperties.drawableRect.topLeft();
1681 NonClientAreaMouseEvent nonClientAreaMouseEvent = {
1682 .timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(event.actionTime),
1683 .action = optAction.value(),
1684 .button = tryMapMouseEventButtonToQt(event.button).value_or(Qt::NoButton),
1685 .displayPosition = event.displayPosition,
1686 .localPosition = event.displayPosition - windowOrigin,
1687 .globalPosition = event.globalPosition,
1688 };
1689
1690 mouseEventsConsumer(nonClientAreaMouseEvent);
1691}
1692
1693void QOhosWindowProxy::JsScopeData::NonClientAreaEventsDispatcher::onTouchEventFromArkUi(const QArkUi::TouchEvent &event) const
1694{
1695 if (touchEventsConsumer == nullptr)
1696 return;
1697
1698 auto optAction = tryMapTouchEventActionToNonClientAreaEventType(event.action);
1699 if (!optAction.has_value())
1700 return;
1701
1702 auto optWindowProperties = QArkUi::tryGetWindowProperties(event.jsWindowId);
1703 if (!optWindowProperties.has_value()) {
1704 qOhosPrintfError(
1705 "%s: Failed to retrieve window properties for js window: %f. Ignoring event.",
1706 Q_FUNC_INFO, event.jsWindowId.value());
1707 return;
1708 }
1709
1710 const auto &windowProperties = optWindowProperties.value();
1711 if (!isPointInNonClientArea(event.displayPosition, windowProperties))
1712 return;
1713
1714 auto windowOrigin = windowProperties.windowRect.topLeft() + windowProperties.drawableRect.topLeft();
1715 NonClientAreaTouchEvent nonClientAreaTouchEvent = {
1716 .id = event.fingerId,
1717 .timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(event.actionTime),
1718 .action = optAction.value(),
1719 .displayPosition = event.displayPosition,
1720 .localPosition = event.displayPosition - windowOrigin,
1721 .globalPosition = event.globalPosition,
1722 };
1723
1724 touchEventsConsumer(nonClientAreaTouchEvent);
1725}
1726
1727QPixmap QOhosWindowProxy::snapshot() const
1728{
1729 return QOhosJsThreadGateway::evalWithPromise<QPixmap>(
1730 [&](QOhosJsState &, QOhosTaskPromise<QPixmap> evalPromise) {
1731 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
1732 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("snapshot()")
1733 .onThen(
1734 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
1735 auto napiPixmap = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1736
1737 ::OH_PixelmapNative *pixelMapNativePtr;
1738 QArkUi::callArkUiOrFailOnErrorResult(
1739 Q_OHOS_NAMED_FUNC(::OH_PixelmapNative_ConvertPixelmapNativeFromNapi),
1740 cbInfo.Env(), napiPixmap, &pixelMapNativePtr);
1741 auto pixelMap = wrapOhosNativePixelMapPtr(pixelMapNativePtr);
1742
1743 thenPromise(
1744 QPixmap::fromImage(createQImageFromNativePixelMap(pixelMap.get())));
1745 })
1746 .onCatch(
1747 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
1748 QtOhos::logJsCallbackError(cbInfo, "Got error from snapshot()");
1749 catchPromise(QPixmap());
1750 });
1751 },
1752 Q_FUNC_INFO);
1753}
1754
1755QList<QRect> QOhosWindowProxy::getDisplayCutoutRects() const
1756{
1757 // The display cutout (e.g. camera hole) is not in getWindowAvoidArea(); read
1758 // it from the display. Returns the bounding rects in display coordinates.
1759 return QOhosJsThreadGateway::evalWithPromise<QList<QRect>>(
1760 [&](QOhosJsState &jsState, QOhosTaskPromise<QList<QRect>> evalPromise) {
1761 if (m_jsScopeData->isWindowClosing()) {
1762 evalPromise(QList<QRect>());
1763 return;
1764 }
1765
1766 auto optWindowDisplay = qAndThen(
1767 getWindowPropertiesFromJsWindow(
1768 m_jsScopeData->jsWindowRef->jsObject()).displayId,
1769 [&](QOhosDisplayInfo::JsDisplayId id) {
1770 return QOhosDisplayInfo::tryGetDisplayById(jsState, id);
1771 });
1772 auto display = optWindowDisplay.has_value()
1773 ? optWindowDisplay.value()
1774 : jsState.eval<QNapi::Object>("@ohos.display.getDefaultDisplaySync()");
1775
1776 auto branches = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
1777 display
1778 .evalToPromiseOrRejectOnThrow("getCutoutInfo()")
1779 .onThen(
1780 [thenPromise = std::move(branches.first)](const QtOhos::CallbackInfo &cbInfo) {
1781 auto cutoutInfo = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1782 auto cutoutRects = QNapi::getArrayElements<QList<QRect>, QNapi::Object>(
1783 cutoutInfo.get<QNapi::Array>("boundingRects"), [](QNapi::Object r) {
1784 return QRect(r.get<QNapi::Number>("left"),
1785 r.get<QNapi::Number>("top"),
1786 r.get<QNapi::Number>("width"),
1787 r.get<QNapi::Number>("height"));
1788 });
1789 thenPromise(cutoutRects);
1790 })
1791 .onCatch(
1792 [catchPromise = std::move(branches.second)](const QtOhos::CallbackInfo &cbInfo) {
1793 QtOhos::logJsCallbackError(cbInfo, "getCutoutInfo() failed");
1794 catchPromise(QList<QRect>());
1795 });
1796 },
1797 Q_FUNC_INFO);
1798}
1799
1800bool QOhosWindowProxy::startMoving()
1801{
1802 QOhosJsThreadGateway::invokeAndWaitForContinue(
1803 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1804 if (m_jsScopeData->isWindowClosing()) {
1805 taskPromise();
1806 return;
1807 }
1808
1809 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("startMoving()")
1810 .onCatch(QtOhos::makeErrorLoggingJsCallback("startMoving()"))
1811 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1812 },
1813 Q_FUNC_INFO);
1814
1815 return true;
1816}
1817
1818void QOhosWindowProxy::enableDrag(bool enable)
1819{
1820 qCDebug(QtForOhos, "%s: %s", Q_FUNC_INFO, QtOhos::mapBoolToTrueFalseStr(enable));
1821
1822 if (qtIsMainWindow()) {
1823 qCWarning(QtForOhos(), "%s: enableDrag is not supported on main windows", Q_FUNC_INFO);
1824 return;
1825 }
1826
1827 QOhosJsThreadGateway::invokeAndWaitForContinue(
1828 [&](QOhosJsState &, QOhosTaskPromise<> taskPromise) {
1829 if (m_jsScopeData->isWindowClosing()) {
1830 taskPromise();
1831 return;
1832 }
1833 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow("enableDrag(*)", {enable})
1834 .onCatch(QtOhos::makeErrorLoggingJsCallback("enableDrag()"))
1835 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1836 },
1837 Q_FUNC_INFO);
1838}
1839
1840std::optional<bool> QOhosWindowProxy::isFocused() const
1841{
1842 return QOhosJsThreadGateway::eval(
1843 [&](QOhosJsState &) -> std::optional<bool> {
1844 if (m_jsScopeData->isWindowClosing())
1845 return std::nullopt;
1846
1847 return m_jsScopeData->jsWindowRef->eval<QNapi::Boolean>("isFocused()");
1848 },
1849 Q_FUNC_INFO);
1850}
1851
1852std::vector<QArkUi::JsWindowId> QOhosWindowProxy::queryWindowIdsByCoordinate(
1853 QOhosDisplayInfo::JsDisplayId displayId, const QPoint &queryLocation, std::uint32_t queryLimit)
1854{
1855 return QOhosJsThreadGateway::evalWithPromise<std::vector<QArkUi::JsWindowId>>(
1856 [&](QOhosJsState &jsState, auto evalPromise) {
1857 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
1858 jsState.evalToPromiseOrRejectOnThrow("@ohos.window.getWindowsByCoordinate(*)", {
1859 displayId.value(),
1860 queryLimit,
1861 queryLocation.x(),
1862 queryLocation.y()
1863 })
1864 .onThen([thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
1865 auto windowsArray = cbInfo.getFirstArg<QNapi::Array>(Q_FUNC_INFO);
1866 thenPromise(
1867 QNapi::getArrayElements<std::vector<QArkUi::JsWindowId>, QNapi::Object>(
1868 windowsArray,
1869 [&](QNapi::Object jsWindow) {
1870 return getWindowPropertiesFromJsWindow(jsWindow).id;
1871 }));
1872 })
1873 .onCatch([catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
1874 QtOhos::logJsCallbackError(
1875 cbInfo, "got error from @ohos.window.getWindowsByCoordinate()");
1876 catchPromise({});
1877 });
1878 },
1879 Q_FUNC_INFO);
1880}
1881
1882std::vector<QArkUi::JsWindowId> QOhosWindowProxy::queryQtManagedWindowIdsByPredicate(
1883 const std::function<bool(QOhosJsState &, const QArkUi::JsWindowRef &)> &predicate)
1884{
1885 return QOhosJsThreadGateway::eval([&](QOhosJsState &jsState) {
1886 return QOhosJsWindowRegistry::instance(jsState).queryByPredicate(jsState, predicate);
1887 },
1888 Q_FUNC_INFO);
1889}
1890
1891void QOhosWindowProxy::moveWindowToGlobal(
1892 const QPoint &position, const MoveConfiguration &moveConfiguration)
1893{
1894 QOhosJsThreadGateway::invokeAndWaitForContinue(
1895 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
1896 if (m_jsScopeData->isWindowClosing()) {
1897 taskPromise();
1898 return;
1899 }
1900
1901 auto moveConfigurationObject = toNapiObject(jsState.env(), moveConfiguration);
1902 auto moveConfigurationObjectStr = QNapi::toJsonString(moveConfigurationObject);
1903 qOhosPrintfDebug(
1904 "%s: %d,%d,%s",
1905 Q_FUNC_INFO, position.x(), position.y(),
1906 moveConfigurationObjectStr.c_str());
1907
1908 m_jsScopeData->jsWindowRef->evalToPromiseOrRejectOnThrow(
1909 "moveWindowToGlobal(*)", {position.x(), position.y(), moveConfigurationObject})
1910 .onCatch(QtOhos::makeErrorLoggingJsCallback(Q_FUNC_INFO))
1911 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1912 },
1913 Q_FUNC_INFO);
1914}
1915
1916std::optional<QOhosDisplayInfo::JsDisplayId> QOhosWindowProxy::tryGetMainWindowJsDisplayId() const
1917{
1918 return qtIsMainWindow()
1919 ? getWindowProperties().displayId
1920 : QOhosJsThreadGateway::eval(
1921 [&](QOhosJsState &) {
1922 auto qUiAbilityPeer
1923 = QtOhos::QUiAbilityPeer::tryCastFromQAbilityPeerOrNull(m_jsScopeData->qAbilityPeer);
1924 return qUiAbilityPeer
1925 ? getWindowPropertiesFromJsWindow(qUiAbilityPeer->window()).displayId
1926 : std::nullopt;
1927 },
1928 Q_FUNC_INFO);
1929}
1930
1931void QOhosWindowProxy::shiftAppWindowFocus(QOhosWindowProxy &targetProxy)
1932{
1933 QOhosJsThreadGateway::invokeAndWaitForContinue(
1934 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
1935 if (m_jsScopeData->isWindowClosing() || targetProxy.m_jsScopeData->isWindowClosing()) {
1936 taskPromise();
1937 return;
1938 }
1939
1940 auto srcWindowId = getWindowPropertiesFromJsWindow(m_jsScopeData->jsWindowRef->jsObject()).id;
1941 auto targetWindowId = getWindowPropertiesFromJsWindow(targetProxy.m_jsScopeData->jsWindowRef->jsObject()).id;
1942 jsState.evalToPromiseOrRejectOnThrow(
1943 "@ohos.window.shiftAppWindowFocus(*)", {srcWindowId.value(), targetWindowId.value()})
1944 .onCatch(QtOhos::makeErrorLoggingJsCallback("@ohos.window.shiftAppWindowFocus()"))
1945 .onFinally(std::move(taskPromise).makeChained(Q_FUNC_INFO));
1946 },
1947 Q_FUNC_INFO);
1948}
1949
1950QT_END_NAMESPACE
bool isWindowPcModeEnabled() const
static QOhosSettings & instance()
void setWindowRectAutoSave(bool enabed)
void setSubWindowModalEnabled(ModalityType ModalityType)
QtOhosQpa::enums::ohos::window::MaximizePresentation MaximizePresentation
void setWindowKeepScreenOn(bool keepScreenOn)
void moveWindowToGlobal(const QPoint &position, const MoveConfiguration &moveConfiguration)
static std::shared_ptr< QOhosWindowProxy > createFloatWindow(const FloatWindowCreateInfo &createInfo)
void setWindowMask(const WindowMask &windowMask, const std::optional< QSize > &ohosMaskSizeOverride={})
QArkUi::WindowProperties getWindowProperties() const
void moveWindowToGlobalOrGlobalDisplay(const QPoint &position, std::optional< QOhosDisplayInfo::JsDisplayId > optDisplayId)
void setWindowPrivacyMode(bool privacyMode)
QtOhosQpa::enums::ohos::window::WindowEventType WindowEventType
AvoidArea getWindowAvoidArea(AvoidAreaType type) const
void setWindowLayoutFullScreen(bool isLayoutFullScreen)
std::optional< QOhosDisplayInfo::JsDisplayId > tryGetMainWindowJsDisplayId() const
void enableDrag(bool enable)
void setWindowCornerRadius(double radius)
QOhosWindowProxyExistingMainWindowCreateInfo ExistingMainWindowCreateInfo
void setSupportedWindowModes(const std::set< SupportWindowMode > &supportedWindowModes)
void setWindowSystemBarEnable(const QStringList &names)
std::shared_ptr< QOhosWindowProxy > createSubWindow(const SubWindowCreateInfo &createInfo)
QPixmap snapshot() const
static std::shared_ptr< QOhosWindowProxy > createForExistingMainWindow(const ExistingMainWindowCreateInfo &createInfo)
void setWindowTouchable(bool touchable)
void setTitle(const QString &title)
void setFollowParentMultiScreenPolicy(bool enabled)
void setWindowTopmost(bool topmost)
std::shared_ptr< QXComponentNode > nodeXComponent() const
void setWindowCallbackReceiver(std::unique_ptr< WindowCallbacks > receiver)
void setSubWindowCloseHandler(std::function< void()> handler, bool handlerReturnValue)
std::optional< bool > isFocused() const
QtOhosQpa::enums::ohos::window::ModalityType ModalityType
void setWindowLimits(const QSize &minSize, const QSize &maxSize)
bool isWindowRectAutoSave() const
void setWindowDecorVisible(bool visible)
void showWindow(const ShowWindowOptions &options=ShowWindowOptions())
void shiftAppWindowFocus(QOhosWindowProxy &targetProxy)
QOhosWindowProxySubWindowCreateInfo SubWindowCreateInfo
void setNonClientAreaMouseWindowCallbackReceiver(QObject *contextObject, QOhosConsumer< std::vector< NonClientAreaMouseEvent > > mouseEventBatchConsumer)
QtOhosQpa::enums::ohos::window::AvoidAreaType AvoidAreaType
void setCustomCursor(const QImage &customCursorImage, const QPoint &hotSpot)
void setWindowTitleMoveEnabled(bool enabled)
void setWindowFocusable(bool focusable)
void setWindowBackgroundColor(const QColor &color)
void setSize(const QSize &size)
QOhosWindowProxyMainWindowCreateInfo MainWindowCreateInfo
void setWindowShadowRadius(double radius)
bool qtIsMainWindow() const
QOhosWindowProxyFloatWindowCreateInfo FloatWindowCreateInfo
void setWindowTitleButtonVisible(bool maximizeVisible, bool minimizeVisible, bool closeVisible)
void setPointerStyleSync(const QCursor &cursor)
QList< QRect > getDisplayCutoutRects() const
WindowLimits getWindowLimits() const
std::string qAbilityInstanceId() const
void maximize(MaximizePresentation maximizePresentation)
void setNonClientAreaTouchWindowCallbackReceiver(QObject *contextObject, QOhosConsumer< std::vector< NonClientAreaTouchEvent > > touchEventBatchConsumer)
static std::shared_ptr< QOhosWindowProxy > createMainWindow(const MainWindowCreateInfo &createInfo)
JsState & jsState() const
std::optional< WindowProperties > tryGetWindowProperties(JsWindowId jsWindowId)
Definition window.cpp:28
Combined button and popup list for selecting options.
QRect ohosWindowRectToQRect(const QNapi::Object &ohosWindowRect)
bool isPointInNonClientArea(const QPoint &point, const QArkUi::WindowProperties &windowProperties)
std::optional< QEvent::Type > tryMapMouseEventActionToNonClientAreaEventType(::Input_MouseEventAction action)
std::optional< double > getOptionalNumberPropAsOptionalDouble(const QNapi::Object &object, const std::string &propertyName)
QOhosPointerStyle convertToOhosCursor(Qt::CursorShape shape)
QOhosWindowProxy::AvoidArea mapAvoidAreaFromJs(const QNapi::Object &avoidAreaObject)
std::string mapEnumsToLogString(const EnumsContainer &enums)
std::optional< Qt::MouseButton > tryMapMouseEventButtonToQt(::Input_MouseEventButton button)
bool isWindowClosingFromSystem(QNapi::Object jsWindow, WindowProxyType windowType, std::shared_ptr< QtOhos::QAbilityPeer > abilityPeer)
bool isAbilityTerminating(QNapi::Object ability)
QtOhosQpa::enums::ohos::multimodalInput::pointer::PointerStyle QOhosPointerStyle
QArkUi::WindowProperties getWindowPropertiesFromJsWindow(QNapi::Object jsWindow)
std::function< void(Args...)> makeQtThreadWindowCallbackDelegate(std::function< void(Args...)> QOhosWindowProxy::WindowCallbacks::*memberPtr, std::shared_ptr< QOhosWindowProxy::WindowCallbacks > qtWindowCallbacks)
std::function< void(T)> makeCompressingQtThreadWindowCallbackDelegate(std::function< void(T)> QOhosWindowProxy::WindowCallbacks::*memberPtr, std::shared_ptr< QOhosWindowProxy::WindowCallbacks > qtWindowCallbacks)
QNapi::Object toNapiObject(napi_env env, const QOhosWindowProxy::MoveConfiguration &moveConfiguration)
std::optional< QEvent::Type > tryMapTouchEventActionToNonClientAreaEventType(::Input_TouchEventAction action)
std::string const char * mapBoolToTrueFalseStr(bool value)
QXComponent< QXComponentType::Node > QXComponentNode
Definition qxcomponent.h:44
std::int32_t fingerId
Definition input.h:54
void onTouchEventFromArkUi(const QArkUi::TouchEvent &event) const
void onMouseEventFromArkUi(const QArkUi::MouseEvent &event) const