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