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
qqtembeddedwindownode.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 <qarkui/qqtembeddedwindownode.h>
5
6#include <arkui/native_node.h>
7#include <arkui/native_type.h>
8#include <qarkui/qarkuiutils.h>
9#include <qohosjsmain.h>
10#include <qohosutils.h>
11
13
14namespace QArkUi {
15namespace {
16
17class XComponentCallbackDispatcher
18{
19public:
20 static XComponentCallbackDispatcher &instance();
21
22 XComponentCallbackDispatcher(const XComponentCallbackDispatcher &) = delete;
23 XComponentCallbackDispatcher(XComponentCallbackDispatcher &&) = delete;
24 XComponentCallbackDispatcher &operator=(const XComponentCallbackDispatcher &) = delete;
25 XComponentCallbackDispatcher &operator=(XComponentCallbackDispatcher &&) = delete;
26
27 std::shared_ptr<void> registerCallbackReceiver(
28 ::OH_NativeXComponent *xComponent,
30
31private:
32 XComponentCallbackDispatcher() = default;
33
34 static void handleSurfaceCreated(::OH_NativeXComponent *xComponent, void *window);
35 static void handleSurfaceChanged(::OH_NativeXComponent *xComponent, void *window);
36 static void handleSurfaceDestroyed(::OH_NativeXComponent *xComponent, void *window);
37 static void handleSurfaceTouchEvent(::OH_NativeXComponent *xComponent, void *window);
38 static void handleMouseEvent(::OH_NativeXComponent *xComponent, void *window);
39 static void handleHoverEvent(::OH_NativeXComponent *xComponent, bool hover);
40 static void handleKeyEvent(::OH_NativeXComponent *xComponent, void *window);
41 static QXComponentCallbackReceiver *findCallbackReceiverOrNull(::OH_NativeXComponent *xComponent);
42
43 std::map<::OH_NativeXComponent *, QXComponentCallbackReceiver *> m_receivers;
44};
45
46XComponentCallbackDispatcher &XComponentCallbackDispatcher::instance()
47{
48 static XComponentCallbackDispatcher dispatcher;
49 return dispatcher;
50}
51
52std::shared_ptr<void> XComponentCallbackDispatcher::registerCallbackReceiver(
53 ::OH_NativeXComponent *xComponent, QXComponentCallbackReceiver *receiver)
54{
55 qOhosPrintfDebug("Registering callbacks for xcomponent %p", xComponent);
56
57 if (m_receivers.find(xComponent) != m_receivers.end()) {
58 qOhosPrintfError("XComponent %p callbacks were already registered", xComponent);
59 throw std::runtime_error("Duplicate xcomponent");
60 }
61
62 m_receivers[xComponent] = receiver;
63
64 static ::OH_NativeXComponent_Callback callbacks = {
65 .OnSurfaceCreated = &XComponentCallbackDispatcher::handleSurfaceCreated,
66 .OnSurfaceChanged = &XComponentCallbackDispatcher::handleSurfaceChanged,
67 .OnSurfaceDestroyed = &XComponentCallbackDispatcher::handleSurfaceDestroyed,
68 .DispatchTouchEvent = &XComponentCallbackDispatcher::handleSurfaceTouchEvent,
69 };
70
71 static ::OH_NativeXComponent_MouseEvent_Callback mouseEventCallbacks = {
72 .DispatchMouseEvent = &XComponentCallbackDispatcher::handleMouseEvent,
73 .DispatchHoverEvent = &XComponentCallbackDispatcher::handleHoverEvent,
74 };
75
76 auto lifecycleAndTouchCallbackRegisterStatus = ::OH_NativeXComponent_RegisterCallback(
77 xComponent, &callbacks);
78 if (lifecycleAndTouchCallbackRegisterStatus != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
79 qOhosReportFatalErrorAndAbort(
80 "OH_NativeXComponent_RegisterCallback failed with error: %d",
81 lifecycleAndTouchCallbackRegisterStatus);
82 }
83
85 auto mouseRegisterStatus = ::OH_NativeXComponent_RegisterMouseEventCallback(
86 xComponent,
87 &mouseEventCallbacks);
88 if (mouseRegisterStatus != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
89 qOhosReportFatalErrorAndAbort(
90 "OH_NativeXComponent_RegisterMouseEventCallback failed with error: %d",
91 mouseRegisterStatus);
92 }
93 }
94
96 auto keyRegisterStatus = ::OH_NativeXComponent_RegisterKeyEventCallback(
97 xComponent, &XComponentCallbackDispatcher::handleKeyEvent);
98 if (keyRegisterStatus != ::OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
99 qOhosReportFatalErrorAndAbort(
100 "OH_NativeXComponent_RegisterKeyEventCallback failed with error: %d",
101 keyRegisterStatus);
102 }
103 }
104
105 return QtOhos::makeDestroyNotifier([this, xComponent](){
106 qOhosPrintfDebug("Unregistering callbacks for xcomponent %p", xComponent);
107 m_receivers.erase(xComponent);
108 ::OH_NativeXComponent_RegisterCallback(xComponent, nullptr);
109 ::OH_NativeXComponent_RegisterMouseEventCallback(xComponent, nullptr);
110 ::OH_NativeXComponent_RegisterKeyEventCallback(xComponent, nullptr);
111 });
112}
113
114QXComponentCallbackReceiver *XComponentCallbackDispatcher::findCallbackReceiverOrNull(::OH_NativeXComponent *xComponent)
115{
116 auto &dispatcher = XComponentCallbackDispatcher::instance();
117 auto it = dispatcher.m_receivers.find(xComponent);
118 if (it == dispatcher.m_receivers.end()) {
119 qOhosPrintfDebug("Error: xComponent %p does not have any assigned receiver", xComponent);
120 return nullptr;
121 }
122 return it->second;
123}
124
125void XComponentCallbackDispatcher::handleSurfaceTouchEvent(::OH_NativeXComponent *xComponent, void *window)
126{
127 auto *receiver = findCallbackReceiverOrNull(xComponent);
128 if (receiver != nullptr) {
129 receiver->onInputEvent(
131 reinterpret_cast<::OHNativeWindow *>(window));
132 }
133}
134
135void XComponentCallbackDispatcher::handleHoverEvent(::OH_NativeXComponent *xComponent, bool isHover)
136{
137 auto *receiver = findCallbackReceiverOrNull(xComponent);
138 if (receiver != nullptr)
139 receiver->onHoverEvent(isHover);
140}
141
142
143void XComponentCallbackDispatcher::handleKeyEvent(::OH_NativeXComponent *xComponent, void *window)
144{
145 auto *receiver = findCallbackReceiverOrNull(xComponent);
146 if (receiver != nullptr) {
147 receiver->onInputEvent(
149 reinterpret_cast<::OHNativeWindow *>(window));
150 }
151}
152
153void XComponentCallbackDispatcher::handleMouseEvent(::OH_NativeXComponent *xComponent, void *window)
154{
155 auto *receiver = findCallbackReceiverOrNull(xComponent);
156 if (receiver != nullptr) {
157 receiver->onInputEvent(
159 reinterpret_cast<::OHNativeWindow *>(window));
160 }
161}
162
163void XComponentCallbackDispatcher::handleSurfaceCreated(::OH_NativeXComponent *xComponent, void *window)
164{
165 qOhosPrintfDebug("%s: xc: %p window: %p", Q_FUNC_INFO, xComponent, window);
166 auto *receiver = findCallbackReceiverOrNull(xComponent);
167 if (receiver != nullptr) {
168 receiver->onSurfaceEvent(
170 reinterpret_cast<::OHNativeWindow*>(window));
171 }
172}
173
174void XComponentCallbackDispatcher::handleSurfaceChanged(::OH_NativeXComponent *xComponent, void *window)
175{
176 qOhosPrintfDebug("%s: xc: %p window: %p", Q_FUNC_INFO, xComponent, window);
177 auto *receiver = findCallbackReceiverOrNull(xComponent);
178 if (receiver != nullptr) {
179 receiver->onSurfaceEvent(
181 reinterpret_cast<::OHNativeWindow*>(window));
182 }
183}
184
185void XComponentCallbackDispatcher::handleSurfaceDestroyed(::OH_NativeXComponent *xComponent, void *window)
186{
187 qOhosPrintfDebug("%s: xc: %p window: %p", Q_FUNC_INFO, xComponent, window);
188 auto *receiver = findCallbackReceiverOrNull(xComponent);
189 if (receiver != nullptr) {
190 receiver->onSurfaceEvent(
192 reinterpret_cast<::OHNativeWindow*>(window));
193 }
194}
195
196}
197
199
200std::shared_ptr<QQtEmbeddedWindowNode> QQtEmbeddedWindowNode::createOrFail(const CreateInfo &createInfo)
201{
202 constexpr std::uint32_t transparentArgb8888 = 0;
203
204 auto stackNode = Node::createOrFail(::ARKUI_NODE_STACK);
205 stackNode->setAttributeOrFail(::NODE_STACK_ALIGN_CONTENT, ::ARKUI_ALIGNMENT_TOP_START);
206 stackNode->setAttributeOrFail(::NODE_Z_INDEX, createInfo.zIndex);
207 stackNode->setAttributeOrFail(::NODE_BACKGROUND_COLOR, transparentArgb8888);
208 stackNode->setAttributeOrFail(
209 ::NODE_BLEND_MODE,
210 std::make_tuple(::ARKUI_BLEND_MODE_SRC_OVER, ::BLEND_APPLY_TYPE_FAST));
211 stackNode->setLengthMetricUnitOrFail(::ARKUI_LENGTH_METRIC_UNIT_PX);
212
213 ::ArkUI_NodeAttributeType widthAttribute;
214 ::ArkUI_NodeAttributeType heightAttribute;
215
216 switch (createInfo.sizePolicy) {
217 case SizePolicy::Points:
218 widthAttribute = ::NODE_WIDTH;
219 heightAttribute = ::NODE_HEIGHT;
220 break;
221 case SizePolicy::PercentNormalized:
222 widthAttribute = ::NODE_WIDTH_PERCENT;
223 heightAttribute = ::NODE_HEIGHT_PERCENT;
224 break;
225 }
226
227 stackNode->setAttributeOrFail(
228 widthAttribute,
229 static_cast<float>(createInfo.size.width()));
230 stackNode->setAttributeOrFail(
231 heightAttribute,
232 static_cast<float>(createInfo.size.height()));
233 stackNode->setAttributeOrFail(
234 ::NODE_POSITION,
235 toFloatArray(createInfo.offset));
236
237 auto xComponentNode = Node::createOrFail(::ARKUI_NODE_XCOMPONENT);
238 xComponentNode->setAttributeOrFail(::NODE_XCOMPONENT_TYPE, createInfo.xComponentType);
239 xComponentNode->setAttributeOrFail(::NODE_FOCUS_ON_TOUCH, createInfo.focusOnTouch);
240 xComponentNode->setAttributeOrFail(
241 ::NODE_BACKGROUND_COLOR,
242 createInfo.backgroundColor.hasValue()
243 ? createInfo.backgroundColor.value().rgba()
244 : transparentArgb8888);
245 xComponentNode->setAttributeOrFail(
246 ::NODE_XCOMPONENT_ID,
247 createInfo.xComponentId.stringId());
248 xComponentNode->setAttributeOrFail(
249 ::NODE_BLEND_MODE,
250 std::make_tuple(::ARKUI_BLEND_MODE_SRC_OVER, ::BLEND_APPLY_TYPE_FAST));
251 xComponentNode->setAttributeOrFail(::NODE_FOCUSABLE, createInfo.focusable);
252 xComponentNode->setAttributeOrFail(::NODE_RENDER_FIT, createInfo.renderFit);
253 xComponentNode->setAttributeOrFail(::NODE_Z_INDEX, createInfo.zIndex);
254
255 stackNode->addChildOrFail(*xComponentNode);
256
257 auto windowId = std::make_unique<QtOhos::WindowIdStruct>(QtOhos::WindowIdStruct{
258 .nodeType = ::ArkUI_NodeType::ARKUI_NODE_XCOMPONENT,
259 .content = xComponentNode->handle(),
260 .stack = stackNode->handle(),
261 .nodeOwner = "QT",
262 .nodePrivate = nullptr,
263 });
264
265 auto node = std::shared_ptr<QQtEmbeddedWindowNode>(
266 new QQtEmbeddedWindowNode(std::move(stackNode), std::move(xComponentNode), std::move(windowId)));
267 if (createInfo.optParent.hasValue())
268 node->setParentOrReparent(createInfo.optParent.value());
269
270 node->setNodeVisibility(false);
271
272 return node;
273}
274
275QXComponentRender QQtEmbeddedWindowNode::renderXComponent() const
276{
277 auto *xComponent = ::OH_NativeXComponent_GetNativeXComponent(contentNode().handle());
278 if (xComponent == nullptr)
279 qOhosReportFatalErrorAndAbort("::OH_NativeXComponent_GetNativeXComponent failed");
280 return QXComponentRender(xComponent);
281}
282
283void QQtEmbeddedWindowNode::setCallbackReceiver(
284 std::unique_ptr<QXComponentCallbackReceiver> callbackReceiver)
285{
286 m_callbackReceiver = std::move(callbackReceiver);
287}
288
289void QQtEmbeddedWindowNode::onSurfaceEvent(
290 SurfaceEventType eventType,
291 ::OHNativeWindow *nativeWindow)
292{
293 qOhosPrintfDebug("%s: node: %p eventType: %d surface: %p", Q_FUNC_INFO, this, eventType, nativeWindow);
294 switch (eventType) {
295 case SurfaceEventType::SurfaceCreated:
296 case SurfaceEventType::SurfaceChanged:
297 m_nativeWindow = nativeWindow;
298 break;
299 case SurfaceEventType::SurfaceDestroyed:
300 m_nativeWindow = nullptr;
301 break;
302 }
303
304 if (m_callbackReceiver)
305 m_callbackReceiver->onSurfaceEvent(eventType, nativeWindow);
306}
307
308void QQtEmbeddedWindowNode::onInputEvent(
309 InputEventType inputEventType,
310 ::OHNativeWindow *nativeWindow)
311{
312 if (m_callbackReceiver)
313 m_callbackReceiver->onInputEvent(inputEventType, nativeWindow);
314}
315
316void QQtEmbeddedWindowNode::onHoverEvent(bool isHover)
317{
318 if (m_callbackReceiver)
319 m_callbackReceiver->onHoverEvent(isHover);
320}
321
322void QQtEmbeddedWindowNode::setSurfaceResolution(std::uint32_t width, std::uint32_t height)
323{
324 contentNode().setAttributeOrFail(
325 ::NODE_XCOMPONENT_SURFACE_SIZE,
326 std::array<std::uint32_t, 2>{width, height});
327}
328
329QQtEmbeddedWindowNode::QQtEmbeddedWindowNode(
330 std::unique_ptr<Node> stackNode,
331 std::unique_ptr<Node> xComponentNode,
332 std::unique_ptr<QtOhos::WindowIdStruct> windowId)
333 : QEmbeddedWindowNode(std::move(stackNode), std::move(xComponentNode), std::move(windowId))
334 , m_xComponentCallbackDispatcherToken(
335 XComponentCallbackDispatcher::instance().registerCallbackReceiver(
336 renderXComponent().handle(), this))
337{
338}
339
340QQtEmbeddedWindowNode::~QQtEmbeddedWindowNode() = default;
341
342void QQtEmbeddedWindowNode::setAreaChangeReceiver(QOhosConsumer<AreaChangeEvent> areaChangeReceiver)
343{
344 m_optAreaChangedReceiver = std::move(areaChangeReceiver);
345
346 stackNode().setEventHandler(
347 ::ArkUI_NodeEventType::NODE_EVENT_ON_AREA_CHANGE,
348 [this](::ArkUI_NodeEvent *) {
349 m_optAreaChangedReceiver(
350 AreaChangeEvent {
351 .screenGeometryPixels = nodeScreenGeometryPixels(),
352 .windowRelativeOffsetPixels = windowRelativeOffsetPixels(),
353 .parentRelativeOffsetPixels = parentRelativeOffsetPixels(),
354 });
355 });
356}
357
358void QQtEmbeddedWindowNode::setFocusedChangeReceiver(QOhosConsumer<bool> focusChangedReceiver)
359{
360 m_optFocusedChangedReceiver = std::move(focusChangedReceiver);
361
362 stackNode().setEventHandler(
363 ::ArkUI_NodeEventType::NODE_ON_FOCUS,
364 [this](::ArkUI_NodeEvent *) {
365 m_optFocusedChangedReceiver(true);
366 });
367
368 stackNode().setEventHandler(
369 ::ArkUI_NodeEventType::NODE_ON_BLUR,
370 [this](::ArkUI_NodeEvent *) {
371 m_optFocusedChangedReceiver(false);
372 });
373}
374
375void QQtEmbeddedWindowNode::setVisibilityChangeReceiver(QOhosConsumer<bool> visibilityChangedReceiver)
376{
377 m_optVisibilityChangedReceiver = std::move(visibilityChangedReceiver);
378
379 stackNode().setEventHandler(
380 ::ArkUI_NodeEventType::NODE_EVENT_ON_APPEAR,
381 [this](::ArkUI_NodeEvent *) {
382 m_optVisibilityChangedReceiver(true);
383 });
384
385 stackNode().setEventHandler(
386 ::ArkUI_NodeEventType::NODE_EVENT_ON_DISAPPEAR,
387 [this](::ArkUI_NodeEvent *) {
388 m_optVisibilityChangedReceiver(false);
389 });
390}
391
392void QQtEmbeddedWindowNode::setTouchInterceptReceiver(
393 QOhosConsumer<const ::ArkUI_UIInputEvent *> touchInterceptReceiver)
394{
395 m_optTouchInterceptReceiver = std::move(touchInterceptReceiver);
396 stackNode().setEventHandler(
397 ::ArkUI_NodeEventType::NODE_ON_TOUCH_INTERCEPT,
398 [this](::ArkUI_NodeEvent *nodeEvent) {
399 auto *uiInputEvent = ::OH_ArkUI_NodeEvent_GetInputEvent(nodeEvent);
400 if (uiInputEvent == nullptr)
401 return;
402 m_optTouchInterceptReceiver(uiInputEvent);
403 });
404}
405
406QRect QQtEmbeddedWindowNode::nodeScreenGeometryPixels() const
407{
408 ::ArkUI_IntOffset screenPositionPx;
409 callArkUiOrFailOnErrorResult(
410 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPositionInScreen),
411 stackNode().handle(), &screenPositionPx);
412
413 ::ArkUI_IntSize screenSizePx;
414 callArkUiOrFailOnErrorResult(
415 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutSize),
416 stackNode().handle(), &screenSizePx);
417
418 return QRect(
419 QPoint(screenPositionPx.x, screenPositionPx.y),
420 QSize(screenSizePx.width, screenSizePx.height));
421}
422
423bool QQtEmbeddedWindowNode::hasNonQtManagedChildren() const
424{
425 return QArkUi::Node::tryfindChild(
426 stackNode().handle(),
427 [&](::ArkUI_NodeHandle nodeHandle) {
428 return !QArkUi::Node::isQtManagedNode(nodeHandle);
429 }).hasValue();
430}
431
432QPoint QQtEmbeddedWindowNode::windowRelativeOffsetPixels() const
433{
434 ::ArkUI_IntOffset windowPositionPx;
435 callArkUiOrFailOnErrorResult(
436 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPositionInWindow),
437 stackNode().handle(), &windowPositionPx);
438 return QPoint(windowPositionPx.x, windowPositionPx.y);
439}
440
441QPoint QQtEmbeddedWindowNode::parentRelativeOffsetPixels() const
442{
443 ::ArkUI_IntOffset parentPositionPx;
444 callArkUiOrFailOnErrorResult(
445 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPosition),
446 stackNode().handle(), &parentPositionPx);
447 return QPoint(parentPositionPx.x, parentPositionPx.y);
448}
449
450}
451
452QT_END_NAMESPACE
void setTouchInterceptReceiver(QOhosConsumer< const ::ArkUI_UIInputEvent * > touchInterceptReceiver)
void onHoverEvent(bool isHover) override
void setFocusedChangeReceiver(QOhosConsumer< bool > focus)
void setSurfaceResolution(std::uint32_t width, std::uint32_t height)
void onSurfaceEvent(SurfaceEventType surfaceEventType, ::OHNativeWindow *nativeWindow) override
static std::shared_ptr< QQtEmbeddedWindowNode > createOrFail(const CreateInfo &createInfo)
void setAreaChangeReceiver(QOhosConsumer< AreaChangeEvent > areaChangeReceiver)
void onInputEvent(InputEventType inputEventType, ::OHNativeWindow *nativeWindow) override
void setCallbackReceiver(std::unique_ptr< QXComponentCallbackReceiver > callbackReceiver)
QXComponentRender renderXComponent() const
void setVisibilityChangeReceiver(QOhosConsumer< bool > visibilityChangedReceiver)
Combined button and popup list for selecting options.
bool isNativeNodeApiMouseEventsEnabled()
bool isNativeNodeApiKeyEventsEnabled()
QXComponent< QXComponentType::Render > QXComponentRender
Definition qxcomponent.h:43