Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qjnitypes.h
Go to the documentation of this file.
1// Copyright (C) 2022 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#ifndef QJNITYPES_H
5#define QJNITYPES_H
6
7#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
8
9#include <QtCore/qjnitypes_impl.h>
10#include <QtCore/qjniobject.h>
11
13
14// QT_TECH_PREVIEW_API
15#define Q_DECLARE_JNI_TYPE_HELPER(Type) \
16namespace QtJniTypes { \
17struct Type : JObject<Type> \
18{ \
19 using JObject::JObject; \
20}; \
21} \
22
23// QT_TECH_PREVIEW_API
24#define Q_DECLARE_JNI_TYPE(Type, Signature) \
25Q_DECLARE_JNI_TYPE_HELPER(Type) \
26template<> \
27struct QtJniTypes::Traits<QtJniTypes::Type> { \
28 static constexpr auto signature() \
29 { \
30 static_assert((Signature[0] == 'L' \
31 || Signature[0] == '[') \
32 && Signature[sizeof(Signature) - 2] == ';', \
33 "Type signature needs to start with 'L' or" \
34 " '[' and end with ';'"); \
35 return QtJniTypes::CTString(Signature); \
36 } \
37}; \
38
39// QT_TECH_PREVIEW_API
40#define Q_DECLARE_JNI_CLASS(Type, Signature) \
41Q_DECLARE_JNI_TYPE_HELPER(Type) \
42template<> \
43struct QtJniTypes::Traits<QtJniTypes::Type> { \
44 static constexpr auto className() \
45 { \
46 return QtJniTypes::CTString(Signature); \
47 } \
48 static constexpr auto signature() \
49 { \
50 return QtJniTypes::CTString("L") \
51 + className() \
52 + QtJniTypes::CTString(";"); \
53 } \
54}; \
55
56// Macros for native methods
57
58namespace QtJniMethods {
59namespace Detail {
60// Various helpers to forward a call from a variadic argument function to
61// the real function with proper type conversion. This is needed because we
62// want to write functions that take QJniObjects (subclasses), while Java
63// can only call functions that take jobjects.
64
65// In Var-arg functions, any argument narrower than (unsigned) int or double
66// is promoted to (unsigned) int or double.
67template <typename Arg> struct PromotedType { using Type = Arg; };
68template <> struct PromotedType<bool> { using Type = int; };
69template <> struct PromotedType<char> { using Type = int; };
70template <> struct PromotedType<signed char> { using Type = int; };
71template <> struct PromotedType<unsigned char> { using Type = unsigned int; };
72template <> struct PromotedType<short> { using Type = int; };
73template <> struct PromotedType<unsigned short> { using Type = unsigned int; };
74template <> struct PromotedType<float> { using Type = double; };
75
76// Map any QJniObject type to jobject; that's what's on the va_list
77template <typename Arg>
78struct JNITypeForArgImpl
79{
80 using Type = std::conditional_t<std::disjunction_v<std::is_base_of<QJniObject, Arg>,
81 std::is_base_of<QtJniTypes::JObjectBase, Arg>>,
82 jobject, typename PromotedType<Arg>::Type>;
83 static Arg fromVarArg(Type t)
84 {
85 return static_cast<Arg>(t);
86 }
87};
88
89template <>
90struct JNITypeForArgImpl<QString>
91{
92 using Type = jstring;
93
94 static QString fromVarArg(Type t)
95 {
96 return QJniObject(t).toString();
97 }
98};
99
100template <typename T>
101struct JNITypeForArgImpl<QJniArray<T>>
102{
103 using Type = jobject;
104
105 static QJniArray<T> fromVarArg(Type t)
106 {
107 return QJniArray<T>(t);
108 }
109};
110
111template <typename T>
112struct JNITypeForArgImpl<QList<T>>
113{
114private:
115 using ArrayType = decltype(QJniArrayBase::fromContainer(std::declval<QList<T>>()));
116 using ArrayObjectType = decltype(std::declval<ArrayType>().arrayObject());
117 using ElementType = typename ArrayType::value_type;
118public:
119 using Type = ArrayObjectType;
120
121 static QList<T> fromVarArg(Type t)
122 {
123 return QJniArray<ElementType>(t).toContainer();
124 }
125};
126
127template <typename Arg>
128using JNITypeForArg = typename JNITypeForArgImpl<std::decay_t<Arg>>::Type;
129template <typename Arg, typename Type>
130static inline auto methodArgFromVarArg(Type t) // Type comes from a va_arg, so is always POD
131{
132 return JNITypeForArgImpl<std::decay_t<Arg>>::fromVarArg(t);
133}
134
135// Turn a va_list into a tuple of typed arguments
136template <typename ...Args>
137static constexpr auto makeTupleFromArgsHelper(va_list args)
138{
139 return std::tuple(methodArgFromVarArg<Args>(va_arg(args, JNITypeForArg<Args>))...);
140}
141
142template <typename Ret, typename ...Args>
143static constexpr auto makeTupleFromArgs(Ret (*)(JNIEnv *, jobject, Args...), va_list args)
144{
145 return makeTupleFromArgsHelper<Args...>(args);
146}
147template <typename Ret, typename ...Args>
148static constexpr auto makeTupleFromArgs(Ret (*)(JNIEnv *, jclass, Args...), va_list args)
149{
150 return makeTupleFromArgsHelper<Args...>(args);
151}
152
153// Get the return type of a function point
154template <typename Ret, typename ...Args>
155auto nativeFunctionReturnType(Ret(*function)(Args...))
156{
157 return function(std::declval<Args>()...);
158}
159
160} // namespace Detail
161} // namespace QtJniMethods
162
163// A va_ variadic arguments function that we register with JNI as a proxy
164// for the function we have. This function uses the helpers to unpack the
165// variadic arguments into a tuple of typed arguments, which we then call
166// the actual function with. This then takes care of implicit conversions,
167// e.g. a jobject becomes a QJniObject.
168#define Q_DECLARE_JNI_NATIVE_METHOD_HELPER(Method) \
169static decltype(QtJniMethods::Detail::nativeFunctionReturnType(Method)) \
170va_##Method(JNIEnv *env, jclass thiz, ...) \
171{ \
172 va_list args; \
173 va_start(args, thiz); \
174 auto va_cleanup = qScopeGuard([&args]{ va_end(args); }); \
175 auto argTuple = QtJniMethods::Detail::makeTupleFromArgs(Method, args); \
176 return std::apply([env, thiz](auto &&... args) { \
177 return Method(env, thiz, args...); \
178 }, argTuple); \
179} \
180
181// QT_TECH_PREVIEW_API
182#define Q_DECLARE_JNI_NATIVE_METHOD(...) \
183 QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \
184
185#define QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Name) \
186namespace QtJniMethods { \
187Q_DECLARE_JNI_NATIVE_METHOD_HELPER(Method) \
188static constexpr auto Method##_signature = \
189 QtJniTypes::nativeMethodSignature(Method); \
190static const JNINativeMethod Method##_method = { \
191 #Name, Method##_signature.data(), \
192 reinterpret_cast<void *>(va_##Method) \
193}; \
194} \
195
196#define QT_DECLARE_JNI_NATIVE_METHOD_1(Method) \
197 QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Method) \
198
199// QT_TECH_PREVIEW_API
200#define Q_JNI_NATIVE_METHOD(Method) QtJniMethods::Method##_method
201
202// QT_TECH_PREVIEW_API
203#define Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(...) \
204 QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE, __VA_ARGS__) \
205
206#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Name) \
207 Q_DECLARE_JNI_NATIVE_METHOD_HELPER(Method) \
208 static inline constexpr auto Method##_signature = QtJniTypes::nativeMethodSignature(Method); \
209 static inline const JNINativeMethod Method##_method = { \
210 #Name, Method##_signature.data(), reinterpret_cast<void *>(va_##Method) \
211 };
212
213#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_1(Method) \
214 QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Method) \
215
216// QT_TECH_PREVIEW_API
217#define Q_JNI_NATIVE_SCOPED_METHOD(Method, Scope) Scope::Method##_method
218
220
221#endif // defined(Q_QDOC) || defined(Q_OS_ANDROID)
222
223#endif // QJNITYPES_H
\inmodule QtCore
Definition qlist.h:75
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
Combined button and popup list for selecting options.
std::array< typename ArrayTypeHelper< ManualType, Types... >::type, sizeof...(Types)> ArrayType
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
GLdouble GLdouble t
Definition qopenglext.h:243
QJSValueList args
Definition moc.h:23