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