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 .string = {},
101 .object = {},
102 };
103 setNodeAttributeOrFail(node, attribute, {item});
104}
105
106std::shared_ptr<void> registerNodeEvent(
107 ::ArkUI_NodeHandle node, ::ArkUI_NodeEventType eventType, void *userData)
108{
109 auto registerEventRes = nativeNodeApi().registerNodeEvent(
110 node, eventType, static_cast<std::int32_t>(eventType), userData);
111 if (registerEventRes != ::ARKUI_ERROR_CODE_NO_ERROR) {
112 qOhosReportFatalErrorAndAbort(
113 "QArkUi: registerNodeEvent(%p, %d) failed with error: %d",
114 node, eventType, registerEventRes);
115 }
116
117 return QtOhos::makeDestroyNotifier(
118 [node, eventType]() {
119 nativeNodeApi().unregisterNodeEvent(node, eventType);
120 });
121}
122
123std::shared_ptr<void> addNodeEventReceiver(
124 ::ArkUI_NodeHandle node, void (*eventReceiver)(::ArkUI_NodeEvent *event))
125{
126 auto addEventReceiverRes = nativeNodeApi().addNodeEventReceiver(node, eventReceiver);
127 if (addEventReceiverRes != ::ARKUI_ERROR_CODE_NO_ERROR) {
128 qOhosReportFatalErrorAndAbort(
129 "QArkUi: addNodeEventReceiver(%p, ...) failed with error: %d",
130 node, addEventReceiverRes);
131 }
132
133 return QtOhos::makeDestroyNotifier(
134 [node, eventReceiver]() {
135 nativeNodeApi().removeNodeEventReceiver(node, eventReceiver);
136 });
137}
138
139}
140
141std::set<::ArkUI_NodeHandle> Node::qtManagedNodes;
142
144 ::ArkUI_NodeAttributeType attributeType, float value)
145{
146 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(value)});
147}
148
150 ::ArkUI_NodeAttributeType attributeType, std::int32_t value)
151{
152 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(value)});
153}
154
156 ::ArkUI_NodeAttributeType attributeType, std::uint32_t value)
157{
158 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(value)});
159}
160
162 ::ArkUI_NodeAttributeType attributeType, bool value)
163{
164 std::int32_t intValue = value ? 1 : 0;
165 setNodeAttributeOrFail(handle(), attributeType, {toArkUiNumberValue(intValue)});
166}
167
169 ::ArkUI_NodeAttributeType attributeType, const std::string &value)
170{
171 ::ArkUI_AttributeItem item = {
172 .value = {},
173 .size = {},
174 .string = value.data(),
175 .object = {},
176 };
177 setNodeAttributeOrFail(handle(), attributeType, {item});
178}
179
181{
182 auto errorCode = nativeNodeApi().addChild(handle(), child.handle());
183 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR) {
184 qOhosReportFatalErrorAndAbort(
185 "addChild failed for parent: %p, child: %p with error: %d",
186 handle(),
187 child.handle(),
188 errorCode);
189 }
190}
191
193{
194 return m_node.get();
195}
196
197std::unique_ptr<Node> Node::createOrFail(::ArkUI_NodeType type)
198{
200 if (nativeNode == nullptr)
201 qOhosReportFatalErrorAndAbort("Failed to create native node");
202
203 return std::unique_ptr<Node>(new Node(nativeNode));
204}
205
206Node::Node(::ArkUI_NodeHandle handle)
207 : m_node(
208 handle,
209 [](auto handle) {
210 auto *parentNode = nativeNodeApi().getParent(handle);
211 if (parentNode != nullptr)
212 nativeNodeApi().removeChild(parentNode, handle);
213 nativeNodeApi().disposeNode(handle);
214 std::ignore = qtManagedNodes.erase(handle);
215 })
216{
217 bool added = false;
218 std::tie(std::ignore, added) = qtManagedNodes.insert(handle);
219 if (!added)
220 qOhosReportFatalErrorAndAbort("Attempted to take ownership of ::ArkUI_NodeHandle for a second time.");
221}
222
224{
225 auto errorCode = nativeNodeApi().removeChild(handle(), child.handle());
226 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR)
227 qOhosReportFatalErrorAndAbort("removeChild failed with error: %d", errorCode);
228}
229
231 ::ArkUI_NodeEventType eventType,
232 std::function<void(::ArkUI_NodeEvent *)> eventHandler)
233{
234 if (!m_eventReceiverHandle) {
235 m_eventReceiverHandle = addNodeEventReceiver(
236 handle(),
237 [](ArkUI_NodeEvent *event) {
238 void *userData = ::OH_ArkUI_NodeEvent_GetUserData(event);
239 if (userData == nullptr) {
240 qOhosPrintfWarning("QArkUi: got node event with null userData, ignoring");
241 return;
242 }
243
244 auto *self = reinterpret_cast<Node *>(userData);
245
246 auto eventType = ::OH_ArkUI_NodeEvent_GetEventType(event);
247
248 auto eventHandlerIter = self->m_eventHandlers.find(eventType);
249 if (eventHandlerIter != self->m_eventHandlers.end())
250 eventHandlerIter->second(event);
251 else
252 qOhosPrintfWarning("QArkUi: got node event type %d with no handler set, ignoring", eventType);
253 });
254 }
255
256 m_eventHandlers.erase(eventType);
257
258 auto eventRegistrationHandle = registerNodeEvent(handle(), eventType, this);
259
260 m_eventHandlers.emplace(
261 eventType,
262 [eventRegistrationHandle, eventHandler = std::move(eventHandler)](ArkUI_NodeEvent *event) {
263 eventHandler(event);
264 });
265}
266
267void Node::setAttributeOrFail(
268 ::ArkUI_NodeAttributeType attributeType,
269 std::size_t numberCount, const ::ArkUI_NumberValue *numbers)
270{
271 ::ArkUI_AttributeItem item = {
272 .value = numbers,
273 .size = static_cast<std::int32_t>(numberCount),
274 .string = {},
275 .object = {},
276 };
277
278 setNodeAttributeOrFail(handle(), attributeType, {item});
279}
280
281std::unique_ptr<Node> Node::takeOwnershipOfExternalNode(::ArkUI_NodeHandle nodeHandle)
282{
283 if (nodeHandle == nullptr)
284 qOhosReportFatalErrorAndAbort("nodeHandle must not be null");
285
286 return std::unique_ptr<Node>(new Node(nodeHandle));
287}
288
289bool Node::isQtManagedNode(::ArkUI_NodeHandle nodeHandle)
290{
291 return qtManagedNodes.find(nodeHandle) != qtManagedNodes.end();
292}
293
294::ArkUI_NumberValue Node::getNumberValueAttributeOrFail(::ArkUI_NodeAttributeType attributeType) const
295{
296 const auto *item = nativeNodeApi().getAttribute(handle(), attributeType);
297 if (item == nullptr) {
298 qOhosReportFatalErrorAndAbort(
299 "QArkUi: Failed to retrieve node: %p attribute: %d", handle(), attributeType);
300 }
301 return *item->value;
302}
303
304template<>
309
310void Node::setLengthMetricUnitOrFail(::ArkUI_LengthMetricUnit unit)
311{
312 auto errorCode = nativeNodeApi().setLengthMetricUnit(handle(), unit);
313 if (errorCode != ::ARKUI_ERROR_CODE_NO_ERROR) {
314 qOhosReportFatalErrorAndAbort(
315 "setLengthMetricUnit failed for node: %p with error: %d", handle(), errorCode);
316 }
317}
318
319bool Node::hasParent() const
320{
321 return nativeNodeApi().getParent(handle()) != nullptr;
322}
323
325{
326 auto *parentHandle = nativeNodeApi().getParent(handle());
327 return parentHandle != nullptr
328 ? nativeNodeApi().getTotalChildCount(parentHandle) - 1
329 : 0;
330}
331
332void Node::moveTo(std::uint32_t index)
333{
334 QArkUi::callArkUi(
335 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_MoveTo),
336 handle(), nativeNodeApi().getParent(handle()), index);
337}
338
339std::optional<::ArkUI_NodeHandle> Node::tryfindChild(
340 ::ArkUI_NodeHandle nodeHandle, const std::function<bool(::ArkUI_NodeHandle)> predicate)
341{
342 const auto childCount = nativeNodeApi().getTotalChildCount(nodeHandle);
343 for (std::uint32_t i = 0; i < childCount; ++i) {
344 auto *childNodeHandle = nativeNodeApi().getChildAt(nodeHandle, i);
345 if (predicate(childNodeHandle))
346 return childNodeHandle;
347 }
348 return {};
349}
350
351QPoint Node::nodeGlobalPosition(::ArkUI_NodeHandle nodeHandle)
352{
353 ::ArkUI_IntOffset globalPositionPx;
354 callArkUiOrFailOnErrorResult(
355 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPositionInGlobalDisplay),
356 nodeHandle, &globalPositionPx);
357 return QPoint(globalPositionPx.x, globalPositionPx.y);
358}
359
360QPoint Node::nodeDisplayPosition(::ArkUI_NodeHandle nodeHandle)
361{
362 ::ArkUI_IntOffset displayPosition;
363 callArkUiOrFailOnErrorResult(
364 Q_OHOS_NAMED_FUNC(::OH_ArkUI_NodeUtils_GetLayoutPositionInScreen),
365 nodeHandle, &displayPosition);
366 return QPoint(displayPosition.x, displayPosition.y);
367}
368
369}
370
371QT_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.