2018-02-26 08:09:21 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskMetaCallback.h"
|
2018-02-28 09:43:15 +00:00
|
|
|
|
2018-02-26 08:09:21 +00:00
|
|
|
#include <QObject>
|
2018-02-28 09:43:15 +00:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QThread>
|
|
|
|
#include <QSemaphore>
|
|
|
|
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qobject_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
|
|
|
static inline void qskInvokeMethodQueued( QObject* object,
|
|
|
|
const QMetaObject* metaObject, ushort methodIndex,
|
|
|
|
int nargs, int* types, void* args[], QSemaphore* semaphore = nullptr )
|
|
|
|
{
|
|
|
|
constexpr QObject* sender = nullptr;
|
|
|
|
constexpr int signalId = -1;
|
|
|
|
|
|
|
|
auto event = new QMetaCallEvent(
|
|
|
|
metaObject->methodOffset(), methodIndex, metaObject->d.static_metacall,
|
|
|
|
sender, signalId, nargs, types, args, semaphore );
|
|
|
|
|
|
|
|
QCoreApplication::postEvent( object, event );
|
|
|
|
}
|
2018-02-26 08:09:21 +00:00
|
|
|
|
|
|
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
2018-02-27 16:47:23 +00:00
|
|
|
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
2018-02-26 08:09:21 +00:00
|
|
|
m_object( const_cast< QObject* >( object ) ),
|
2018-02-28 07:37:40 +00:00
|
|
|
m_method( new QMetaMethod( method ) ),
|
2018-02-26 08:09:21 +00:00
|
|
|
m_type( MetaMethod ),
|
|
|
|
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaCallback::QskMetaCallback( const QObject* object,
|
|
|
|
const QskMetaFunction& function, Qt::ConnectionType connectionType ):
|
|
|
|
m_object( const_cast< QObject* >( object ) ),
|
2018-02-28 07:37:40 +00:00
|
|
|
m_function( new QskMetaFunction( function ) ),
|
2018-02-26 08:09:21 +00:00
|
|
|
m_type( MetaFunction ),
|
|
|
|
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaCallback::QskMetaCallback( const QskMetaCallback& other ):
|
|
|
|
m_object( other.m_object ),
|
|
|
|
m_function(),
|
|
|
|
m_type( Invalid ),
|
|
|
|
m_connectionType( other.m_connectionType )
|
|
|
|
{
|
|
|
|
if ( other.m_type != m_type )
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
m_type = other.m_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
2018-02-28 07:37:40 +00:00
|
|
|
m_method = new QMetaMethod( *other.m_method );
|
2018-02-26 08:09:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MetaFunction:
|
2018-02-28 07:37:40 +00:00
|
|
|
m_function = new QskMetaFunction( *other.m_function );
|
2018-02-26 08:09:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaCallback::~QskMetaCallback()
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaCallback& QskMetaCallback::operator=( const QskMetaCallback& other )
|
|
|
|
{
|
|
|
|
m_object = other.m_object;
|
|
|
|
m_connectionType = other.m_connectionType;
|
|
|
|
|
|
|
|
if ( other.m_type != m_type )
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
m_type = other.m_type;
|
|
|
|
}
|
|
|
|
|
2018-02-28 07:37:40 +00:00
|
|
|
if ( other.m_type != Invalid )
|
2018-02-26 08:09:21 +00:00
|
|
|
{
|
2018-02-28 07:37:40 +00:00
|
|
|
if ( other.m_type == MetaMethod )
|
|
|
|
m_method = new QMetaMethod( *other.m_method );
|
|
|
|
else
|
|
|
|
m_function = new QskMetaFunction( *other.m_function );
|
2018-02-26 08:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-02-27 16:47:23 +00:00
|
|
|
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
|
|
|
|
{
|
|
|
|
m_connectionType = connectionType;
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:09:21 +00:00
|
|
|
void QskMetaCallback::reset()
|
|
|
|
{
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
2018-02-28 07:37:40 +00:00
|
|
|
delete m_method;
|
|
|
|
m_method = nullptr;
|
2018-02-26 08:09:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MetaFunction:
|
2018-02-28 07:37:40 +00:00
|
|
|
delete m_function;
|
|
|
|
m_function = nullptr;
|
2018-02-26 08:09:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_type = Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector< int > QskMetaCallback::parameterTypes() const
|
|
|
|
{
|
|
|
|
QVector< int > paramTypes;
|
|
|
|
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
|
|
|
{
|
2018-02-28 07:37:40 +00:00
|
|
|
const int paramCount = m_method->parameterCount();
|
2018-02-26 08:09:21 +00:00
|
|
|
|
|
|
|
paramTypes.reserve( paramCount );
|
|
|
|
for ( int i = 0; i < paramCount; i++ )
|
2018-02-28 07:37:40 +00:00
|
|
|
paramTypes += m_method->parameterType( i );
|
2018-02-26 08:09:21 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
2018-02-28 07:37:40 +00:00
|
|
|
auto types = m_function->parameterTypes();
|
2018-02-26 08:09:21 +00:00
|
|
|
if ( types )
|
|
|
|
{
|
|
|
|
while ( *types )
|
|
|
|
paramTypes += *types++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return paramTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void QskMetaCallback::invoke( void* args[] )
|
|
|
|
{
|
|
|
|
auto object = const_cast< QObject* >( m_object.data() );
|
|
|
|
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
|
|
|
{
|
2018-02-28 09:43:15 +00:00
|
|
|
qskInvokeMethod( object, *m_method, args, connectionType() );
|
2018-02-26 08:09:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
2018-02-28 07:37:40 +00:00
|
|
|
m_function->invoke( object, args, connectionType() );
|
2018-02-26 08:09:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-02-28 09:43:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
void qskInvokeMethod( QObject* object,
|
|
|
|
const QMetaMethod& method, void* args[],
|
|
|
|
Qt::ConnectionType connectionType )
|
|
|
|
{
|
|
|
|
if ( object == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto metaObject = method.enclosingMetaObject();
|
|
|
|
|
|
|
|
const int methodOffset = metaObject->methodOffset();
|
|
|
|
const int methodIndex = method.methodIndex() - methodOffset;
|
|
|
|
|
|
|
|
if ( connectionType == Qt::AutoConnection )
|
|
|
|
{
|
|
|
|
connectionType = ( object->thread() == QThread::currentThread() )
|
|
|
|
? Qt::DirectConnection : Qt::QueuedConnection;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( connectionType == Qt::DirectConnection )
|
|
|
|
{
|
|
|
|
if ( metaObject->d.static_metacall )
|
|
|
|
{
|
|
|
|
metaObject->d.static_metacall(object,
|
|
|
|
QMetaObject::InvokeMetaMethod, methodIndex, args );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QMetaObject::metacall( object,
|
|
|
|
QMetaObject::InvokeMetaMethod, methodIndex, args );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const int paramCount = method.parameterCount();
|
|
|
|
|
|
|
|
auto types = static_cast< int* >( malloc( paramCount * sizeof( int ) ) );
|
|
|
|
auto arguments = static_cast< void** >( malloc( paramCount * sizeof( void* ) ) );
|
|
|
|
|
|
|
|
types[0] = QMetaType::UnknownType; // a return type is not possible
|
|
|
|
arguments[0] = nullptr;
|
|
|
|
|
|
|
|
for ( int i = 1; i < paramCount; i++ )
|
|
|
|
{
|
|
|
|
if ( arguments[i] == nullptr )
|
|
|
|
{
|
|
|
|
Q_ASSERT( arguments[i] != nullptr );
|
|
|
|
|
|
|
|
free( types );
|
|
|
|
free( arguments );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
types[i] = method.parameterType( i );
|
|
|
|
arguments[i] = args[i - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_ASSERT( args[paramCount] == nullptr );
|
|
|
|
|
|
|
|
if ( connectionType == Qt::QueuedConnection )
|
|
|
|
{
|
|
|
|
qskInvokeMethodQueued( object,
|
|
|
|
metaObject, methodIndex, paramCount + 1, types, args );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QSemaphore semaphore;
|
|
|
|
|
|
|
|
qskInvokeMethodQueued( object,
|
|
|
|
metaObject, methodIndex, paramCount + 1, types, args, &semaphore );
|
|
|
|
|
|
|
|
semaphore.acquire();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|