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
qnativenodeapi.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/qnativenodeapi.h>
5
6#include <QtCore/private/qohoslogger_p.h>
7#include <arkui/native_interface.h>
8#include <arkui/native_node.h>
9#include <arkui/native_type.h>
10#include <qarkui/qarkuiutils.h>
11#include <qohosutils.h>
12
14
15namespace QArkUi {
16namespace {
17
18const ::ArkUI_NativeNodeAPI_1 &nativeNodeApi()
19{
20 static const ::ArkUI_NativeNodeAPI_1 api = []() {
21 // NOTE - The pointer ownership here is unclear.
22 // Because there is no information in the docs, assuming that the native interface
23 // manages the pointer.
24 auto *nativeNodeApi = reinterpret_cast<::ArkUI_NativeNodeAPI_1 *>(
25 ::OH_ArkUI_QueryModuleInterfaceByName(::ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
26
27 if (nativeNodeApi == nullptr)
28 qOhosReportFatalErrorAndAbort("::OH_ArkUI_QueryModuleInterface failed");
29
30 static constexpr auto requiredNonNullFunctionPointersMembers = std::make_tuple(
31 &::ArkUI_NativeNodeAPI_1::addChild,
32 &::ArkUI_NativeNodeAPI_1::addNodeEventReceiver,
33 &::ArkUI_NativeNodeAPI_1::createNode,
34 &::ArkUI_NativeNodeAPI_1::disposeNode,
35 &::ArkUI_NativeNodeAPI_1::getAttribute,
36 &::ArkUI_NativeNodeAPI_1::getChildAt,
37 &::ArkUI_NativeNodeAPI_1::getParent,
38 &::ArkUI_NativeNodeAPI_1::getTotalChildCount,
39 &::ArkUI_NativeNodeAPI_1::registerNodeEvent,
40 &::ArkUI_NativeNodeAPI_1::removeChild,
41 &::ArkUI_NativeNodeAPI_1::removeNodeEventReceiver,
42 &::ArkUI_NativeNodeAPI_1::setAttribute,
43 &::ArkUI_NativeNodeAPI_1::unregisterNodeEvent);
44
45 QtOhos::tupleForEach(requiredNonNullFunctionPointersMembers, [&](auto functionMemberPointer) {
46 if ((nativeNodeApi->*functionMemberPointer) == nullptr)
47 qOhosReportFatalErrorAndAbort("Required function is null");
48 });
49
50 return *nativeNodeApi;
51 }();
52
53 return api;
54}
55
56::ArkUI_NumberValue toArkUiNumberValue(std::int32_t value)
57{
58 return ::ArkUI_NumberValue {
59 .i32 = value,
60 };
61}
62
63::ArkUI_NumberValue toArkUiNumberValue(std::uint32_t value)
64{
65 return ::ArkUI_NumberValue {
66 .u32 = value,
67 };
68}
69
70::ArkUI_NumberValue toArkUiNumberValue(float value)
71{
72 return ::ArkUI_NumberValue {
73 .f32 = value,
74 };
75}
76
77void setNodeAttributeOrFail(
78 ::ArkUI_NodeHandle node,
79 ::ArkUI_NodeAttributeType attribute,
80 std::initializer_list<::ArkUI_AttributeItem> values)
81{
82 auto errorCode = nativeNodeApi().setAttribute(node, attribute, values.begin());
83 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR) {
84 qOhosReportFatalErrorAndAbort(
85 "Failed to set attribute: %d on node: %p with error: %d",
86 attribute,
87 node,
88 errorCode);
89 }
90}
91
92void setNodeAttributeOrFail(
93 ::ArkUI_NodeHandle node,
94 ::ArkUI_NodeAttributeType attribute,
95 std::initializer_list<::ArkUI_NumberValue> values)
96{
97 ::ArkUI_AttributeItem item = {
98 .value = values.begin(),
99 .size = static_cast<std::int32_t>(values.size()),
100 };
101 setNodeAttributeOrFail(node, attribute, {item});
102}
103
104std::shared_ptr<void> registerNodeEvent(
105 ::ArkUI_NodeHandle node, ::ArkUI_NodeEventType eventType, void *userData)
106{
107 auto registerEventRes = nativeNodeApi().registerNodeEvent(
108 node, eventType, static_cast<std::int32_t>(eventType), userData);
109 if (registerEventRes != ::ARKUI_ERROR_CODE_NO_ERROR) {
110 qOhosReportFatalErrorAndAbort(
111 "QArkUi: registerNodeEvent(%p, %d) failed with error: %d",
112 node, eventType, registerEventRes);
113 }
114
115 return QtOhos::makeDestroyNotifier(
116 [node, eventType]() {
117 nativeNodeApi().unregisterNodeEvent(node, eventType);
118 });
119}
120
121std::shared_ptr<void> addNodeEventReceiver(
122 ::ArkUI_NodeHandle node, void (*eventReceiver)(::ArkUI_NodeEvent *event))
123{
124 auto addEventReceiverRes = nativeNodeApi().addNodeEventReceiver(node, eventReceiver);
125 if (addEventReceiverRes != ::ARKUI_ERROR_CODE_NO_ERROR) {
126 qOhosReportFatalErrorAndAbort(
127 "QArkUi: addNodeEventReceiver(%p, ...) failed with error: %d",
128 node, addEventReceiverRes);
129 }
130
131 return QtOhos::makeDestroyNotifier(
132 [node, eventReceiver]() {
133 nativeNodeApi().removeNodeEventReceiver(node, eventReceiver);
134 });
135}
136
137}
138
139std::set<::ArkUI_NodeHandle> Node::qtManagedNodes;
140
142 ::ArkUI_NodeAttributeType attributeType, float value)
143{
144 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(value)});
145}
146
148 ::ArkUI_NodeAttributeType attributeType, std::int32_t value)
149{
150 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(value)});
151}
152
154 ::ArkUI_NodeAttributeType attributeType, std::uint32_t value)
155{
156 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(value)});
157}
158
160 ::ArkUI_NodeAttributeType attributeType, bool value)
161{
162 std::int32_t intValue = value ? 1 : 0;
163 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(intValue)});
164}
165
167 ::ArkUI_NodeAttributeType attributeType, const std::string &value)
168{
169 ::ArkUI_AttributeItem item = {
170 .string = value.data(),
171 };
172 setNodeAttributeOrFail(handle(), attributeType, {item});
173}
174
176{
177 auto errorCode = nativeNodeApi().addChild(handle(), child.handle());
178 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR) {
179 qOhosReportFatalErrorAndAbort(
180 "addChild failed for parent: %p, child: %p with error: %d",
181 handle(),
182 child.handle(),
183 errorCode);
184 }
185}
186
188{
189 return m_node.get();
190}
191
192std::unique_ptr<Node> Node::createOrFail(::ArkUI_NodeType type)
193{
195 if (nativeNode == nullptr)
196 qOhosReportFatalErrorAndAbort("Failed to create native node");
197
198 return std::unique_ptr<Node>(new Node(nativeNode));
199}
200
201Node::Node(::ArkUI_NodeHandle handle)
202 : m_node(
203 handle,
204 [](auto handle) {
205 auto *parentNode = nativeNodeApi().getParent(handle);
206 if (parentNode != nullptr)
207 nativeNodeApi().removeChild(parentNode, handle);
208 nativeNodeApi().disposeNode(handle);
209 std::ignore = qtManagedNodes.erase(handle);
210 })
211{
212 bool added = false;
213 std::tie(std::ignore, added) = qtManagedNodes.insert(handle);
214 if (!added)
215 qOhosReportFatalErrorAndAbort("Attempted to take ownership of ::ArkUI_NodeHandle for a second time.");
216}
217
219{
220 auto errorCode = nativeNodeApi().removeChild(handle(), child.handle());
221 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR)
222 qOhosReportFatalErrorAndAbort("removeChild failed with error: %d", errorCode);
223}
224
226 ::ArkUI_NodeEventType eventType,
227 std::function<void(::ArkUI_NodeEvent *)> eventHandler)
228{
229 if (!m_eventReceiverHandle) {
230 m_eventReceiverHandle = addNodeEventReceiver(
231 handle(),
232 [](ArkUI_NodeEvent *event) {
233 void *userData = ::OH_ArkUI_NodeEvent_GetUserData(event);
234 if (userData == nullptr) {
235 qOhosPrintfWarning("QArkUi: got node event with null userData, ignoring");
236 return;
237 }
238
239 auto *self = reinterpret_cast<Node *>(userData);
240
241 auto eventType = ::OH_ArkUI_NodeEvent_GetEventType(event);
242
243 auto eventHandlerIter = self->m_eventHandlers.find(eventType);
244 if (eventHandlerIter != self->m_eventHandlers.end())
245 eventHandlerIter->second(event);
246 else
247 qOhosPrintfWarning("QArkUi: got node event type %d with no handler set, ignoring", eventType);
248 });
249 }
250
251 m_eventHandlers.erase(eventType);
252
253 auto eventRegistrationHandle = registerNodeEvent(handle(), eventType, this);
254
255 m_eventHandlers.emplace(
256 eventType,
257 [eventRegistrationHandle, eventHandler = std::move(eventHandler)](ArkUI_NodeEvent *event) {
258 eventHandler(event);
259 });
260}
261
262void Node::setAttributeOrFail(
263 ::ArkUI_NodeAttributeType attributeType,
264 std::size_t numberCount, const ::ArkUI_NumberValue *numbers)
265{
266 ::ArkUI_AttributeItem item = {
267 .value = numbers,
268 .size = static_cast<std::int32_t>(numberCount),
269 };
270
271 setNodeAttributeOrFail(handle(), attributeType, {item});
272}
273
274std::unique_ptr<Node> Node::takeOwnershipOfExternalNode(::ArkUI_NodeHandle nodeHandle)
275{
276 if (nodeHandle == nullptr)
277 qOhosReportFatalErrorAndAbort("nodeHandle must not be null");
278
279 return std::unique_ptr<Node>(new Node(nodeHandle));
280}
281
282bool Node::isQtManagedNode(::ArkUI_NodeHandle nodeHandle)
283{
284 return qtManagedNodes.find(nodeHandle) != qtManagedNodes.end();
285}
286
287::ArkUI_NumberValue Node::getNumberValueAttributeOrFail(::ArkUI_NodeAttributeType attributeType) const
288{
289 const auto *item = nativeNodeApi().getAttribute(handle(), attributeType);
290 if (item == nullptr) {
291 qOhosReportFatalErrorAndAbort(
292 "QArkUi: Failed to retrieve node: %p attribute: %d", handle(), attributeType);
293 }
294 return *item->value;
295}
296
297template<>
302
303void Node::setLengthMetricUnitOrFail(::ArkUI_LengthMetricUnit unit)
304{
305 auto errorCode = nativeNodeApi().setLengthMetricUnit(handle(), unit);
306 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR) {
307 qOhosReportFatalErrorAndAbort(
308 "setLengthMetricUnit failed for node: %p with error: %d", handle(), errorCode);
309 }
310}
311
312bool Node::hasParent() const
313{
314 return nativeNodeApi().getParent(handle()) != nullptr;
315}
316
318{
319 auto *parentHandle = nativeNodeApi().getParent(handle());
320 return parentHandle != nullptr
321 ? nativeNodeApi().getTotalChildCount(parentHandle) - 1
322 : 0;
323}
324
325void Node::moveTo(std::uint32_t index)
326{
327 QArkUi::callArkUi(
328 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_MoveTo),
329 handle(), nativeNodeApi().getParent(handle()), index);
330}
331
332QOhosOptional<::ArkUI_NodeHandle> Node::tryfindChild(
333 ::ArkUI_NodeHandle nodeHandle, const std::function<bool(::ArkUI_NodeHandle)> predicate)
334{
335 const auto childCount = nativeNodeApi().getTotalChildCount(nodeHandle);
336 for (std::uint32_t i = 0; i < childCount; ++i) {
337 auto *childNodeHandle = nativeNodeApi().getChildAt(nodeHandle, i);
338 if (predicate(childNodeHandle))
339 return makeQOhosOptional(childNodeHandle);
340 }
342}
343
344QPoint Node::nodeGlobalPosition(::ArkUI_NodeHandle nodeHandle)
345{
346 ::ArkUI_IntOffset globalPositionPx;
347 callArkUiOrFailOnErrorResult(
348 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPositionInGlobalDisplay),
349 nodeHandle, &globalPositionPx);
350 return QPoint(globalPositionPx.x, globalPositionPx.y);
351}
352
353QPoint Node::nodeDisplayPosition(::ArkUI_NodeHandle nodeHandle)
354{
355 ::ArkUI_IntOffset displayPosition;
356 callArkUiOrFailOnErrorResult(
357 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPositionInScreen),
358 nodeHandle, &displayPosition);
359 return QPoint(displayPosition.x, displayPosition.y);
360}
361
362}
363
364QT_END_NAMESPACE
std::uint32_t siblingsCount() const
void setAttributeOrFail(::ArkUI_NodeAttributeType attributeType, bool value)
void setAttributeOrFail(::ArkUI_NodeAttributeType attributeType, std::uint32_t value)
bool hasParent() const
void setAttributeOrFail(::ArkUI_NodeAttributeType attributeType, std::int32_t value)
void moveTo(std::uint32_t index)
void setAttributeOrFail(::ArkUI_NodeAttributeType attributeType, const std::string &value)
void setEventHandler(::ArkUI_NodeEventType eventType, std::function< void(::ArkUI_NodeEvent *)> eventHandler)
::ArkUI_NodeHandle handle() const
void removeChildOrFail(Node &child)
void setLengthMetricUnitOrFail(::ArkUI_LengthMetricUnit unit)
void setAttributeOrFail(::ArkUI_NodeAttributeType attributeType, float value)
void addChildOrFail(Node &child)
std::int32_t Node::getAttributeOrFail< std::int32_t >(::ArkUI_NodeAttributeType attributeType) const
Combined button and popup list for selecting options.
std::nullopt_t makeEmptyQOhosOptional()