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