6#include "QskMetaInvokable.h"
7#include "QskMetaFunction.h"
9#include <qmetaobject.h>
11#include <qcoreapplication.h>
15#include <qsemaphore.h>
19#include <private/qobject_p.h>
22static void qskRegisterMetaInvokable()
24 qRegisterMetaType< QskMetaInvokable >();
27Q_CONSTRUCTOR_FUNCTION( qskRegisterMetaInvokable )
31 using CallFunction = QObjectPrivate::StaticMetaCallFunction;
36 inline Function(
void* functionCall )
41 static inline void ref(
void* functionCall )
44 static_cast< FunctionCall*
>( functionCall )->ref();
47 static inline void deref(
void* functionCall )
50 static_cast< FunctionCall*
>( functionCall )->destroyIfLastRef();
54 class MetaCallEvent final :
public QMetaCallEvent
57 MetaCallEvent( QMetaObject::Call call,
const QMetaObject* metaObject,
58 ushort offset, ushort index,
void* args[], QSemaphore* semaphore )
59 : QMetaCallEvent( offset, index,
60 metaObject->d.static_metacall, nullptr, -1, args, semaphore )
62 , m_callFunction( metaObject->d.static_metacall )
67 MetaCallEvent( QMetaObject::Call call,
const QMetaObject* metaObject,
68 ushort offset, ushort index,
int argc )
69 : QMetaCallEvent( offset, index,
70 metaObject->d.static_metacall, nullptr, -1, argc )
72 , m_callFunction( metaObject->d.static_metacall )
77 void placeMetaCall( QObject*
object )
override
79 m_callFunction(
object, m_call, m_index, args() );
83 const QMetaObject::Call m_call;
86 CallFunction m_callFunction;
91QMetaMethod qskMetaMethod(
const QObject*
object,
const char* methodName )
93 return object ? qskMetaMethod( object->metaObject(), methodName ) : QMetaMethod();
96QMetaMethod qskMetaMethod(
const QMetaObject* metaObject,
const char* methodName )
98 if ( metaObject ==
nullptr || methodName ==
nullptr )
101 constexpr char signalIndicator =
'0' + QSIGNAL_CODE;
102 constexpr char slotIndicator =
'0' + QSLOT_CODE;
106 if ( methodName[ 0 ] == signalIndicator )
108 auto signature = QMetaObject::normalizedSignature( methodName + 1 );
109 index = metaObject->indexOfSignal( signature );
111 else if ( methodName[ 0 ] == slotIndicator )
113 auto signature = QMetaObject::normalizedSignature( methodName + 1 );
114 index = metaObject->indexOfSlot( signature );
118 auto signature = QMetaObject::normalizedSignature( methodName );
119 index = metaObject->indexOfMethod( signature );
122 return ( index >= 0 ) ? metaObject->method( index ) : QMetaMethod();
125QMetaMethod qskNotifySignal(
const QObject*
object,
const char* propertyName )
127 return object ? qskNotifySignal( object->metaObject(), propertyName ) : QMetaMethod();
130QMetaMethod qskNotifySignal(
const QMetaObject* metaObject,
const char* propertyName )
132 if ( metaObject ==
nullptr || propertyName ==
nullptr )
133 return QMetaMethod();
135 const int propertyIndex = metaObject->indexOfProperty( propertyName );
138 const auto property = metaObject->property( propertyIndex );
139 return property.notifySignal();
142 return QMetaMethod();
145static void qskInvokeMetaCall(
146 QObject*
object,
const QMetaObject* metaObject,
147 QMetaObject::Call call, ushort offset, ushort index,
void* args[],
148 Qt::ConnectionType connectionType )
150 QPointer< QObject > receiver(
object );
152 int invokeType = connectionType & 0x3;
154 if ( invokeType == Qt::AutoConnection )
156 invokeType = (
object &&
object->thread() != QThread::currentThread() )
157 ? Qt::QueuedConnection : Qt::DirectConnection;
160 switch ( invokeType )
162 case Qt::DirectConnection:
164 if ( receiver.isNull() )
177 metaObject->d.static_metacall( receiver, call, index, args );
180 case Qt::BlockingQueuedConnection:
182 if ( receiver.isNull() ||
183 ( receiver->thread() == QThread::currentThread() ) )
190 QSemaphore semaphore;
192 auto event =
new MetaCallEvent( call, metaObject,
193 offset, index, args, &semaphore );
196 auto event =
new MetaCallEvent( call, metaObject,
197 offset, index, args,
nullptr );
200 QCoreApplication::postEvent( receiver, event );
208 case Qt::QueuedConnection:
210 if ( receiver ==
nullptr )
213 MetaCallEvent*
event =
nullptr;
215 if ( call == QMetaObject::InvokeMetaMethod )
219 const auto method = metaObject->method( offset + index );
221 const int argc = method.parameterCount() + 1;
223 event =
new MetaCallEvent( call, metaObject, offset, index, argc );
230 auto types =
event->types();
231 auto arguments =
event->args();
233#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
234 types[0] = QMetaType();
235 arguments[ 0 ] =
nullptr;
238 arguments[ 0 ] =
nullptr;
240 for (
int i = 1; i < argc; i++ )
242 if ( args[ i ] ==
nullptr )
244 Q_ASSERT( args[ i ] !=
nullptr );
249 const auto type = method.parameterType( i - 1 );
250 const auto arg = args[ i ];
252#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
253 types[ i ] = QMetaType( type );
254 arguments[ i ] = QMetaType( type ).create( arg );
257 arguments[ i ] = QMetaType::create( type, arg );
264 const auto property = metaObject->property( offset + index );
266 event =
new MetaCallEvent( call, metaObject, offset, index, 1 );
268 const auto type =
property.userType();
269 const auto arg = args[ 0 ];
271#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
272 event->types()[0] = QMetaType( type );
273 event->args()[ 0 ] = QMetaType( type ).create( arg );
275 event->types()[0] = type;
276 event->args()[ 0 ] = QMetaType::create( type, arg );
281 QCoreApplication::postEvent( receiver, event );
290void qskInvokeMetaPropertyWrite( QObject* context,
const QMetaProperty& property,
291 void* args[], Qt::ConnectionType connectionType )
293 qskInvokeMetaPropertyWrite( context, property.enclosingMetaObject(),
294 property.propertyIndex(), args, connectionType );
297void qskInvokeMetaPropertyWrite( QObject* context,
const QMetaObject* metaObject,
298 int propertyIndex,
void* args[], Qt::ConnectionType connectionType )
302 if ( metaObject && ( propertyIndex >= 0 ) &&
303 ( propertyIndex < metaObject->propertyCount() ) )
305 const auto offset = metaObject->propertyOffset();
306 const auto index = propertyIndex - offset;
308 qskInvokeMetaCall( context, metaObject, QMetaObject::WriteProperty,
309 offset, index, args + 1, connectionType );
313void qskInvokeMetaMethod( QObject*
object,
314 const QMetaMethod& method,
void* args[],
315 Qt::ConnectionType connectionType )
317 qskInvokeMetaMethod(
object, method.enclosingMetaObject(),
318 method.methodIndex(), args, connectionType );
321void qskInvokeMetaMethod( QObject*
object,
322 const QMetaObject* metaObject,
int methodIndex,
void* args[],
323 Qt::ConnectionType connectionType )
325 if ( metaObject && ( methodIndex >= 0 ) &&
326 ( methodIndex < metaObject->methodCount() ) )
328 const auto offset = metaObject->methodOffset();
329 const auto index = methodIndex - offset;
331 qskInvokeMetaCall(
object, metaObject, QMetaObject::InvokeMetaMethod,
332 offset, index, args, connectionType );
336QskMetaInvokable::QskMetaInvokable(
const QMetaMethod& method )
337 : m_metaData{ method.enclosingMetaObject(), method.methodIndex() }
338 , m_type( MetaMethod )
342QskMetaInvokable::QskMetaInvokable(
const QObject*
object,
const char* methodName )
347QskMetaInvokable::QskMetaInvokable(
const QMetaObject* metaObject,
const char* methodName )
352QskMetaInvokable::QskMetaInvokable(
const QMetaProperty& property )
353 : m_metaData{ property.enclosingMetaObject(), property.propertyIndex() }
354 , m_type( MetaProperty )
359 : m_functionData{ function.functionCall() }
360 , m_type( MetaFunction )
362 Function::ref( m_functionData.functionCall );
366 : m_type( other.m_type )
373 m_metaData.metaObject = other.m_metaData.metaObject;
374 m_metaData.index = other.m_metaData.index;
380 m_functionData.functionCall = other.m_functionData.functionCall;
381 Function::ref( m_functionData.functionCall );
391QskMetaInvokable::~QskMetaInvokable()
393 if ( m_type == MetaFunction )
394 Function::deref( m_functionData.functionCall );
399 switch ( other.m_type )
404 if ( m_type == MetaFunction )
405 Function::deref( m_functionData.functionCall );
407 m_metaData.metaObject = other.m_metaData.metaObject;
408 m_metaData.index = other.m_metaData.index;
414 if ( m_type == MetaFunction )
415 Function::deref( m_functionData.functionCall );
417 m_functionData.functionCall = other.m_functionData.functionCall;
418 Function::ref( m_functionData.functionCall );
424 if ( m_type == MetaFunction )
425 Function::deref( m_functionData.functionCall );
428 m_type = other.m_type;
435 if ( m_type != other.m_type )
443 return ( m_metaData.metaObject == other.m_metaData.metaObject ) &&
444 ( m_metaData.index == other.m_metaData.index );
448 return m_functionData.functionCall == other.m_functionData.functionCall;
457bool QskMetaInvokable::isNull()
const
464 const auto& d = m_metaData;
466 if ( d.metaObject ==
nullptr || d.index < 0 )
469 const int count = ( m_type == MetaMethod )
470 ? d.metaObject->methodCount() : d.metaObject->propertyCount();
472 return d.index >= count;
476 return m_functionData.functionCall ==
nullptr;
484void QskMetaInvokable::reset()
486 if ( m_type == MetaFunction )
487 Function::deref( m_functionData.functionCall );
492int QskMetaInvokable::parameterCount()
const
499 const auto method = QskMetaInvokable::method();
500 return method.parameterCount();
508 return function().parameterCount();
517int QskMetaInvokable::parameterType(
int index )
const
523 const auto method = QskMetaInvokable::method();
524 return method.parameterType( index );
528 const auto property = QskMetaInvokable::property();
529 return property.userType();
533 auto types = function().parameterTypes();
534 return types[ index ];
538 return QMetaType::UnknownType;
543int QskMetaInvokable::returnType()
const
549 return method().returnType();
553 return function().returnType();
557 return QMetaType::Void;
561 return QMetaType::Void;
566QByteArray QskMetaInvokable::name()
const
572 return method().name();
576 return property().name();
590QMetaMethod QskMetaInvokable::method()
const
592 if ( m_type == MetaMethod && m_metaData.metaObject )
593 return m_metaData.metaObject->method( m_metaData.index );
595 return QMetaMethod();
598QMetaProperty QskMetaInvokable::property()
const
600 if ( m_type == MetaProperty && m_metaData.metaObject )
601 return m_metaData.metaObject->property( m_metaData.index );
603 return QMetaProperty();
608 if ( m_type == MetaFunction && m_functionData.functionCall )
610 Function function( m_functionData.functionCall );
617void QskMetaInvokable::invoke( QObject*
object,
void* args[],
618 Qt::ConnectionType connectionType )
627 qskInvokeMetaMethod(
object, m_metaData.metaObject,
628 m_metaData.index, args, connectionType );
634 qskInvokeMetaPropertyWrite(
635 object, m_metaData.metaObject, m_metaData.index, args, connectionType );
641 if ( m_functionData.functionCall )
643 Function function( m_functionData.functionCall );
644 function.invoke(
object, args, connectionType );