QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskMetaFunction.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskMetaFunction.h"
7
8#include <qcoreapplication.h>
9#include <qobject.h>
10#include <qthread.h>
11
12#if QT_CONFIG(thread)
13#include <qsemaphore.h>
14#endif
15
16QSK_QT_PRIVATE_BEGIN
17#include <private/qobject_p.h>
18QSK_QT_PRIVATE_END
19
20namespace
21{
22 using FunctionCall = QskMetaFunction::FunctionCall;
23
24 // to have access to the private section of QSlotObjectBase
25 struct SlotObject
26 {
27 QAtomicInt ref;
28 FunctionCall::InvokeFunction invoke;
29 const int* parameterTypes;
30 };
31
32 static_assert( sizeof( SlotObject ) == sizeof( FunctionCall ),
33 "Bad cast: QskMetaFunction does not match" );
34}
35
36int QskMetaFunction::FunctionCall::typeInfo() const
37{
38 auto that = const_cast< FunctionCall* >( this );
39
40 int value;
41
42 reinterpret_cast< SlotObject* >( that )->invoke(
43 TypeInfo, that, nullptr, reinterpret_cast< void** >( &value ), nullptr );
44
45 return value;
46}
47
48int QskMetaFunction::FunctionCall::refCount() const
49{
50 auto that = const_cast< FunctionCall* >( this );
51 return reinterpret_cast< SlotObject* >( that )->ref.loadRelaxed();
52}
53
54QskMetaFunction::QskMetaFunction()
55 : m_functionCall( nullptr )
56{
57}
58
59QskMetaFunction::QskMetaFunction( FunctionCall* functionCall )
60 : m_functionCall( functionCall )
61{
62 if ( m_functionCall )
63 m_functionCall->ref();
64}
65
66QskMetaFunction::QskMetaFunction( const QskMetaFunction& other )
67 : m_functionCall( other.m_functionCall )
68{
69 if ( m_functionCall )
70 m_functionCall->ref();
71}
72
73QskMetaFunction::QskMetaFunction( QskMetaFunction&& other )
74 : m_functionCall( other.m_functionCall )
75{
76 other.m_functionCall = nullptr;
77}
78
79QskMetaFunction::~QskMetaFunction()
80{
81 if ( m_functionCall )
82 m_functionCall->destroyIfLastRef();
83}
84
85QskMetaFunction& QskMetaFunction::operator=( QskMetaFunction&& other )
86{
87 if ( m_functionCall != other.m_functionCall )
88 {
89 if ( m_functionCall )
90 m_functionCall->destroyIfLastRef();
91
92 m_functionCall = other.m_functionCall;
93 other.m_functionCall = nullptr;
94 }
95
96 return *this;
97}
98
99QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
100{
101 if ( m_functionCall != other.m_functionCall )
102 {
103 if ( m_functionCall )
104 m_functionCall->destroyIfLastRef();
105
106 m_functionCall = other.m_functionCall;
107
108 if ( m_functionCall )
109 m_functionCall->ref();
110 }
111
112 return *this;
113}
114
115bool QskMetaFunction::operator==( const QskMetaFunction& other ) const
116{
117 if ( m_functionCall == other.m_functionCall )
118 return true;
119
120 /*
121 There is no way to compmare functors/members without
122 std::type_info, what we don't want to use as it is
123 another template creating symbols.
124
125 So this implementation can't do much more than finding
126 out if one instance is a copy from another.
127 */
128
129 if ( m_functionCall && other.m_functionCall )
130 {
131 if ( m_functionCall->typeInfo() == StaticFunction &&
132 other.m_functionCall->typeInfo() == StaticFunction )
133 {
134 // only static functions can be compared
135 return m_functionCall->compare(
136 reinterpret_cast< void** >( other.m_functionCall ) );
137 }
138 }
139
140 return false;
141}
142
143int QskMetaFunction::returnType() const
144{
145 return QMetaType::Void; // TODO ...
146}
147
148size_t QskMetaFunction::parameterCount() const
149{
150 size_t count = 0;
151
152 if ( auto types = parameterTypes() )
153 {
154 while ( types[ count ] != QMetaType::UnknownType )
155 count++;
156 }
157
158 return count;
159}
160
161QskMetaFunction::Type QskMetaFunction::functionType() const
162{
163 if ( m_functionCall == nullptr )
164 return Invalid;
165
166 return static_cast< QskMetaFunction::Type >( m_functionCall->typeInfo() );
167}
168
169void QskMetaFunction::invoke( QObject* object,
170 void* argv[], Qt::ConnectionType connectionType )
171{
172#if 1
173 /*
174 Since Qt 5.10 we also have QMetaObject::invokeMethod
175 with functor based callbacks. TODO ...
176 */
177#endif
178
179 // code is not thread safe - TODO ...
180
181 if ( m_functionCall == nullptr )
182 return;
183
184 QPointer< QObject > receiver( object );
185
186 int invokeType = connectionType & 0x3;
187
188 if ( invokeType == Qt::AutoConnection )
189 {
190 invokeType = ( receiver && receiver->thread() != QThread::currentThread() )
191 ? Qt::QueuedConnection : Qt::DirectConnection;
192 }
193
194 switch ( invokeType )
195 {
196 case Qt::DirectConnection:
197 {
198 m_functionCall->call( receiver, argv );
199 break;
200 }
201 case Qt::BlockingQueuedConnection:
202 {
203 if ( receiver.isNull() ||
204 ( receiver->thread() == QThread::currentThread() ) )
205 {
206 // We would end up in a deadlock, better do nothing
207 return;
208 }
209
210#if QT_CONFIG(thread)
211 QSemaphore semaphore;
212
213 auto event = new QMetaCallEvent(
214 m_functionCall, nullptr, 0, argv, &semaphore );
215#else
216 auto event = new QMetaCallEvent(
217 m_functionCall, nullptr, 0, argv, nullptr );
218#endif
219
220 QCoreApplication::postEvent( receiver, event );
221
222#if QT_CONFIG(thread)
223 semaphore.acquire();
224#endif
225
226 break;
227 }
228 case Qt::QueuedConnection:
229 {
230 if ( receiver.isNull() )
231 return;
232
233 const auto argc = parameterCount() + 1; // return value + arguments
234
235 auto event = new QMetaCallEvent( m_functionCall, nullptr, 0, argc );
236
237 auto types = event->types();
238 auto arguments = event->args();
239
240#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
241 types[0] = QMetaType();
242 arguments[ 0 ] = nullptr;
243#else
244 types[0] = 0;
245 arguments[ 0 ] = nullptr;
246#endif
247
248 const int* parameterTypes = m_functionCall->parameterTypes();
249 for ( uint i = 1; i < argc; i++ )
250 {
251 if ( argv[ i ] == nullptr )
252 {
253 Q_ASSERT( arguments[ i ] != nullptr );
254 receiver = nullptr;
255 break;
256 }
257
258 const auto type = parameterTypes[i - 1];
259
260#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
261 types[ i ] = QMetaType( type );
262 arguments[ i ] = QMetaType( type ).create( argv[ i ] );
263#else
264 types[ i ] = type;
265 arguments[ i ] = QMetaType::create( type, argv[ i ] );
266#endif
267 }
268
269 if ( receiver )
270 QCoreApplication::postEvent( receiver, event );
271 else
272 delete event;
273
274 break;
275 }
276 }
277}
278
279#include "moc_QskMetaFunction.cpp"