2018-02-26 09:09:21 +01:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskGlobal.h"
|
|
|
|
#include "QskMetaFunction.h"
|
|
|
|
|
2018-02-28 10:43:15 +01:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QThread>
|
|
|
|
#include <QObject>
|
|
|
|
#include <QSemaphore>
|
|
|
|
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qobject_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
|
|
|
static inline void qskInvokeFunctionQueued( QObject* object,
|
|
|
|
QskMetaInvokable* invokable, int argc, int* types, void* argv[],
|
|
|
|
QSemaphore* semaphore = nullptr )
|
|
|
|
{
|
|
|
|
constexpr QObject* sender = nullptr;
|
|
|
|
constexpr int signalId = 0;
|
|
|
|
|
|
|
|
auto event = new QMetaCallEvent(
|
|
|
|
invokable, sender, signalId, argc, types, argv, semaphore );
|
|
|
|
|
|
|
|
QCoreApplication::postEvent( object, event );
|
|
|
|
}
|
|
|
|
|
2018-02-26 09:09:21 +01:00
|
|
|
QskMetaFunction::QskMetaFunction():
|
2018-03-02 06:57:08 +01:00
|
|
|
m_invokable( nullptr )
|
2018-02-26 09:09:21 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-03-02 06:57:08 +01:00
|
|
|
QskMetaFunction::QskMetaFunction( QskMetaInvokable* invokable ):
|
|
|
|
m_invokable( invokable )
|
2018-02-28 16:48:46 +01:00
|
|
|
{
|
|
|
|
if ( m_invokable )
|
|
|
|
m_invokable->ref();
|
|
|
|
}
|
|
|
|
|
2018-02-26 09:09:21 +01:00
|
|
|
QskMetaFunction::QskMetaFunction( const QskMetaFunction& other ):
|
2018-03-02 06:57:08 +01:00
|
|
|
m_invokable( other.m_invokable )
|
2018-02-26 09:09:21 +01:00
|
|
|
{
|
|
|
|
if ( m_invokable )
|
|
|
|
m_invokable->ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaFunction::QskMetaFunction( QskMetaFunction&& other ):
|
2018-03-02 06:57:08 +01:00
|
|
|
m_invokable( other.m_invokable )
|
2018-02-26 09:09:21 +01:00
|
|
|
{
|
|
|
|
other.m_invokable = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaFunction::~QskMetaFunction()
|
|
|
|
{
|
|
|
|
if ( m_invokable )
|
|
|
|
m_invokable->destroyIfLastRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaFunction& QskMetaFunction::operator=( QskMetaFunction&& other )
|
|
|
|
{
|
|
|
|
if ( m_invokable != other.m_invokable )
|
|
|
|
{
|
|
|
|
if ( m_invokable )
|
|
|
|
m_invokable->destroyIfLastRef();
|
|
|
|
|
|
|
|
m_invokable = other.m_invokable;
|
|
|
|
other.m_invokable = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaFunction& QskMetaFunction::operator=( const QskMetaFunction& other )
|
|
|
|
{
|
|
|
|
if ( m_invokable != other.m_invokable )
|
|
|
|
{
|
|
|
|
if ( m_invokable )
|
|
|
|
m_invokable->destroyIfLastRef();
|
|
|
|
|
|
|
|
m_invokable = other.m_invokable;
|
|
|
|
|
|
|
|
if ( m_invokable )
|
|
|
|
m_invokable->ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-02-27 17:47:23 +01:00
|
|
|
size_t QskMetaFunction::parameterCount() const
|
|
|
|
{
|
2018-03-02 06:57:08 +01:00
|
|
|
if ( auto types = parameterTypes() )
|
2018-02-27 17:47:23 +01:00
|
|
|
{
|
2018-03-01 12:18:58 +01:00
|
|
|
for ( int i = 1;; i++ )
|
2018-02-27 17:47:23 +01:00
|
|
|
{
|
2018-03-02 06:57:08 +01:00
|
|
|
if ( types[ i ] == QMetaType::UnknownType )
|
2018-02-27 17:47:23 +01:00
|
|
|
return i + 1; // including the return type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1; // we always have a return type
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-26 09:09:21 +01:00
|
|
|
QskMetaFunction::Type QskMetaFunction::functionType() const
|
|
|
|
{
|
|
|
|
if ( m_invokable == nullptr )
|
|
|
|
return Invalid;
|
|
|
|
|
|
|
|
return static_cast< QskMetaFunction::Type >( m_invokable->typeInfo() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskMetaFunction::invoke(
|
2018-02-27 17:47:23 +01:00
|
|
|
QObject* object, void* argv[], Qt::ConnectionType connectionType )
|
2018-02-26 09:09:21 +01:00
|
|
|
{
|
2018-03-02 11:26:25 +01:00
|
|
|
// code is not thread safe - TODO ...
|
|
|
|
|
2018-03-02 14:58:43 +01:00
|
|
|
QPointer< QObject > receiver( object );
|
2018-03-02 11:26:25 +01:00
|
|
|
|
2018-02-28 10:43:15 +01:00
|
|
|
if ( m_invokable == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
int invokeType = connectionType & 0x3;
|
|
|
|
|
|
|
|
if ( invokeType == Qt::AutoConnection )
|
|
|
|
{
|
2018-03-02 11:26:25 +01:00
|
|
|
invokeType = ( receiver && receiver->thread() != QThread::currentThread() )
|
2018-02-28 16:48:46 +01:00
|
|
|
? Qt::QueuedConnection : Qt::DirectConnection;
|
2018-02-28 10:43:15 +01:00
|
|
|
}
|
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
switch( invokeType )
|
2018-02-27 17:47:23 +01:00
|
|
|
{
|
2018-03-02 11:26:25 +01:00
|
|
|
case Qt::DirectConnection:
|
2018-02-28 10:43:15 +01:00
|
|
|
{
|
2018-03-02 11:26:25 +01:00
|
|
|
m_invokable->call( receiver, argv );
|
|
|
|
break;
|
2018-02-28 10:43:15 +01:00
|
|
|
}
|
2018-03-02 11:26:25 +01:00
|
|
|
case Qt::BlockingQueuedConnection:
|
|
|
|
{
|
|
|
|
if ( receiver.isNull()
|
|
|
|
|| ( receiver->thread() == QThread::currentThread() ) )
|
|
|
|
{
|
|
|
|
// We would end up in a deadlock, better do nothing
|
|
|
|
return;
|
|
|
|
}
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
QSemaphore semaphore;
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
qskInvokeFunctionQueued( receiver, m_invokable,
|
|
|
|
0, nullptr, argv, &semaphore );
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
semaphore.acquire();
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Qt::QueuedConnection:
|
2018-02-28 10:43:15 +01:00
|
|
|
{
|
2018-03-02 11:26:25 +01:00
|
|
|
if ( receiver.isNull() )
|
2018-02-28 10:43:15 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
const auto argc = parameterCount();
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
auto types = static_cast< int* >( malloc( argc * sizeof( int ) ) );
|
|
|
|
auto arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) );
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
types[0] = QMetaType::UnknownType; // a return type is not possible
|
|
|
|
arguments[0] = nullptr;
|
2018-02-28 10:43:15 +01:00
|
|
|
|
2018-03-02 11:26:25 +01:00
|
|
|
const int* parameterTypes = m_invokable->parameterTypes();
|
|
|
|
for ( uint i = 1; i < argc; i++ )
|
|
|
|
{
|
|
|
|
if ( argv[i] == nullptr )
|
|
|
|
{
|
|
|
|
Q_ASSERT( arguments[i] != nullptr );
|
|
|
|
receiver = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
types[i] = parameterTypes[i - 1];
|
|
|
|
arguments[i] = QMetaType::create( parameterTypes[i - 1], argv[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( receiver.isNull() )
|
|
|
|
{
|
|
|
|
// object might have died in the meantime
|
|
|
|
free( types );
|
|
|
|
free( arguments );
|
2018-03-02 14:58:43 +01:00
|
|
|
|
|
|
|
return;
|
2018-03-02 11:26:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qskInvokeFunctionQueued( object, m_invokable, argc, types, arguments );
|
|
|
|
break;
|
2018-02-28 10:43:15 +01:00
|
|
|
}
|
2018-02-27 17:47:23 +01:00
|
|
|
}
|
2018-02-26 09:09:21 +01:00
|
|
|
}
|
2018-02-28 16:48:46 +01:00
|
|
|
|
|
|
|
#include "moc_QskMetaFunction.cpp"
|