QskMata classes improved, queued connections for property write
accessors added
This commit is contained in:
parent
c109b170f1
commit
42a09813ed
|
@ -0,0 +1,40 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "Callback.h"
|
||||||
|
#include <QMetaMethod>
|
||||||
|
|
||||||
|
Callback::Callback():
|
||||||
|
m_context( nullptr )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback::Callback( const QObject* context, const QMetaMethod& method ):
|
||||||
|
m_context( const_cast< QObject* >( context ) ),
|
||||||
|
m_invokable( method )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback::Callback( const QObject* context, const char* methodName ):
|
||||||
|
Callback( context, qskMetaMethod( context, methodName ) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback::Callback( const QObject* context, const QMetaProperty& property ):
|
||||||
|
m_context( const_cast< QObject* >( context ) ),
|
||||||
|
m_invokable( property )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback::Callback( const QObject* context, const QskMetaFunction& function ):
|
||||||
|
m_context( const_cast< QObject* >( context ) ),
|
||||||
|
m_invokable( function )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Callback::invoke( void* args[], Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
m_invokable.invoke( m_context, args, connectionType );
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CALLBACK_H
|
||||||
|
#define CALLBACK_H 1
|
||||||
|
|
||||||
|
#include <QskMetaInvokable.h>
|
||||||
|
|
||||||
|
class QObject;
|
||||||
|
|
||||||
|
class Callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Callback();
|
||||||
|
|
||||||
|
Callback( const QObject*, const QskMetaFunction& );
|
||||||
|
Callback( const QObject*, const QMetaMethod& );
|
||||||
|
Callback( const QObject*, const QMetaProperty& );
|
||||||
|
|
||||||
|
Callback( const QObject*, const char* methodName );
|
||||||
|
|
||||||
|
void invoke( void* args[], Qt::ConnectionType );
|
||||||
|
|
||||||
|
const QObject* context() const;
|
||||||
|
const QskMetaInvokable& invokable() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QObject* m_context;
|
||||||
|
QskMetaInvokable m_invokable;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const QObject* Callback::context() const
|
||||||
|
{
|
||||||
|
return m_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const QskMetaInvokable& Callback::invokable() const
|
||||||
|
{
|
||||||
|
return m_invokable;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,21 +16,22 @@ Invoker::Invoker( QObject* parent ):
|
||||||
void Invoker::addFunctionCall( const QObject* object,
|
void Invoker::addFunctionCall( const QObject* object,
|
||||||
const QskMetaFunction& function )
|
const QskMetaFunction& function )
|
||||||
{
|
{
|
||||||
m_callbacks.append( QskMetaCallback( object, function ) );
|
m_callbacks.append( Callback( object, function ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Invoker::addMethodCall( const QObject* object,
|
void Invoker::addMethodCall( const QObject* object,
|
||||||
const char* methodName )
|
const char* methodName )
|
||||||
{
|
{
|
||||||
m_callbacks.append( QskMetaCallback( object, methodName ) );
|
m_callbacks.append( Callback( object, methodName ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Invoker::addPropertyCall( const QObject* object,
|
void Invoker::addPropertyCall( const QObject* object,
|
||||||
const char* property )
|
const char* property )
|
||||||
{
|
{
|
||||||
const auto* mo = object->metaObject();
|
const auto metaProperty = object->metaObject()->property(
|
||||||
auto metaProperty = mo->property( mo->indexOfProperty( property ) );
|
object->metaObject()->indexOfProperty( property ) );
|
||||||
m_callbacks.append( QskMetaCallback( object, metaProperty ) );
|
|
||||||
|
m_callbacks.append( Callback( object, metaProperty ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Invoker::invoke( qreal realValue, int intValue,
|
void Invoker::invoke( qreal realValue, int intValue,
|
||||||
|
@ -69,27 +70,25 @@ void Invoker::invoke( qreal realValue, int intValue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.setConnectionType( connectionType );
|
switch( connectionType & 0x3 )
|
||||||
|
|
||||||
const int callType = connectionType & 0x3;
|
|
||||||
switch( callType )
|
|
||||||
{
|
{
|
||||||
case Qt::DirectConnection:
|
case Qt::DirectConnection:
|
||||||
{
|
{
|
||||||
callback.invoke( args );
|
callback.invoke( args, connectionType );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::QueuedConnection:
|
case Qt::QueuedConnection:
|
||||||
{
|
{
|
||||||
if ( callback.object() )
|
if ( callback.context() )
|
||||||
callback.invoke( args );
|
callback.invoke( args, connectionType );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Qt::BlockingQueuedConnection:
|
case Qt::BlockingQueuedConnection:
|
||||||
{
|
{
|
||||||
const auto receiver = callback.object();
|
const auto receiver = callback.context();
|
||||||
if ( receiver && receiver->thread() != QThread::currentThread() )
|
if ( receiver && receiver->thread() != QThread::currentThread() )
|
||||||
callback.invoke( args );
|
callback.invoke( args, connectionType );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#ifndef INVOKER_H
|
#ifndef INVOKER_H
|
||||||
#define INVOKER_H 1
|
#define INVOKER_H 1
|
||||||
|
|
||||||
|
#include "Callback.h"
|
||||||
#include <QskMetaFunction.h>
|
#include <QskMetaFunction.h>
|
||||||
#include <QskMetaCallback.h>
|
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
@ -26,7 +26,7 @@ public:
|
||||||
void invoke( qreal d, int i, Qt::ConnectionType );
|
void invoke( qreal d, int i, Qt::ConnectionType );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector< QskMetaCallback > m_callbacks;
|
QVector< Callback > m_callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void Invoker::addFunctionCall( const QskMetaFunction& function )
|
inline void Invoker::addFunctionCall( const QskMetaFunction& function )
|
||||||
|
|
|
@ -5,8 +5,10 @@ QMAKE_MOC_OPTIONS += -nw # disable warning about missing READ
|
||||||
TARGET = invoker
|
TARGET = invoker
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
Callback.h \
|
||||||
Invoker.h
|
Invoker.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
Callback.cpp \
|
||||||
Invoker.cpp \
|
Invoker.cpp \
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
||||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "QskMetaCallback.h"
|
|
||||||
#include "QskMetaMethod.h"
|
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
|
||||||
const QMetaMethod& method, Qt::ConnectionType connectionType ):
|
|
||||||
m_object( const_cast< QObject* >( object ) ),
|
|
||||||
m_invokable( method ),
|
|
||||||
m_hasObject( object != nullptr ),
|
|
||||||
m_connectionType( static_cast< ushort >( connectionType & 0x3 ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
|
||||||
const char* methodName, Qt::ConnectionType connectionType ):
|
|
||||||
QskMetaCallback( object, QskMetaMethod::method( object, methodName ), connectionType )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
|
||||||
const QMetaProperty& property, Qt::ConnectionType connectionType ):
|
|
||||||
m_object( const_cast< QObject* >( object ) ),
|
|
||||||
m_invokable( property ),
|
|
||||||
m_hasObject( object != nullptr ),
|
|
||||||
m_connectionType( static_cast< ushort >( connectionType & 0x3 ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QskMetaCallback::QskMetaCallback( const QObject* object,
|
|
||||||
const QskMetaFunction& function, Qt::ConnectionType connectionType ):
|
|
||||||
m_object( const_cast< QObject* >( object ) ),
|
|
||||||
m_invokable( function ),
|
|
||||||
m_hasObject( object != nullptr ),
|
|
||||||
m_connectionType( static_cast< ushort >( connectionType & ~Qt::UniqueConnection ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QskMetaCallback::~QskMetaCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QskMetaCallback::isValid() const
|
|
||||||
{
|
|
||||||
if ( m_hasObject && m_object.isNull() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !m_invokable.isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaCallback::setInvokable( const QskMetaInvokable& invokable )
|
|
||||||
{
|
|
||||||
// type checking is m_object matches ???
|
|
||||||
m_invokable = invokable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaCallback::setConnectionType( Qt::ConnectionType connectionType )
|
|
||||||
{
|
|
||||||
m_connectionType = connectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaCallback::invoke( void* args[] )
|
|
||||||
{
|
|
||||||
if ( isValid() )
|
|
||||||
m_invokable.invoke( m_object, args, connectionType() );
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
||||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QSK_META_CALLBACK_H
|
|
||||||
#define QSK_META_CALLBACK_H 1
|
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
|
||||||
#include "QskMetaInvokable.h"
|
|
||||||
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class QSK_EXPORT QskMetaCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QskMetaCallback();
|
|
||||||
|
|
||||||
QskMetaCallback( const QObject*, const QskMetaFunction&,
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
QskMetaCallback( const QObject*, const QMetaMethod&,
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
QskMetaCallback( const QObject*, const QMetaProperty&,
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
QskMetaCallback( const QObject*, const char* methodName,
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
~QskMetaCallback();
|
|
||||||
|
|
||||||
bool isValid() const;
|
|
||||||
bool isStale() const;
|
|
||||||
|
|
||||||
const QObject* object() const { return m_object; }
|
|
||||||
|
|
||||||
void setInvokable( const QskMetaInvokable& );
|
|
||||||
const QskMetaInvokable& invokable() const;
|
|
||||||
|
|
||||||
void setConnectionType( Qt::ConnectionType );
|
|
||||||
Qt::ConnectionType connectionType() const;
|
|
||||||
|
|
||||||
void invoke( void* args[] );
|
|
||||||
|
|
||||||
private:
|
|
||||||
QPointer< QObject > m_object;
|
|
||||||
QskMetaInvokable m_invokable;
|
|
||||||
|
|
||||||
bool m_hasObject : 1;
|
|
||||||
ushort m_connectionType : 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline QskMetaCallback::QskMetaCallback():
|
|
||||||
m_hasObject( false )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool QskMetaCallback::isStale() const
|
|
||||||
{
|
|
||||||
return m_hasObject && m_object.isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const QskMetaInvokable& QskMetaCallback::invokable() const
|
|
||||||
{
|
|
||||||
return m_invokable;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Qt::ConnectionType QskMetaCallback::connectionType() const
|
|
||||||
{
|
|
||||||
return static_cast< Qt::ConnectionType >( m_connectionType );
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE( QskMetaCallback )
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -5,15 +5,25 @@
|
||||||
|
|
||||||
#include "QskMetaInvokable.h"
|
#include "QskMetaInvokable.h"
|
||||||
#include "QskMetaFunction.h"
|
#include "QskMetaFunction.h"
|
||||||
#include "QskMetaMethod.h"
|
|
||||||
|
|
||||||
#include <QMetaMethod>
|
#include <QMetaMethod>
|
||||||
|
#include <QMetaProperty>
|
||||||
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QSemaphore>
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qobject_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
using CallFunction = QObjectPrivate::StaticMetaCallFunction;
|
||||||
|
|
||||||
class Function : public QskMetaFunction
|
class Function : public QskMetaFunction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -34,33 +44,270 @@ namespace
|
||||||
static_cast< FunctionCall* >( functionCall )->destroyIfLastRef();
|
static_cast< FunctionCall* >( functionCall )->destroyIfLastRef();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MetaCallEvent final : public QMetaCallEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MetaCallEvent( QMetaObject::Call call, CallFunction callFunction,
|
||||||
|
ushort offset, ushort index,
|
||||||
|
int nargs, int* types, void* args[], QSemaphore* semaphore = nullptr ):
|
||||||
|
QMetaCallEvent( offset, index, callFunction, nullptr, -1,
|
||||||
|
nargs, types, args, semaphore ),
|
||||||
|
m_call( call ),
|
||||||
|
m_callFunction( callFunction ),
|
||||||
|
m_index( index )
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qskInvokeSetProperty( QObject* object,
|
virtual void placeMetaCall( QObject* object ) override final
|
||||||
const QMetaObject* metaObject, int propertyIndex,
|
|
||||||
void* args[], Qt::ConnectionType connectionType )
|
|
||||||
{
|
{
|
||||||
|
m_callFunction( object, m_call, m_index, args() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QMetaObject::Call m_call;
|
||||||
|
|
||||||
|
// as those members from QMetaCallEvent are not accessible
|
||||||
|
CallFunction m_callFunction;
|
||||||
|
const ushort m_index;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void qskInvokeMetaCallQueued( QObject* object,
|
||||||
|
QMetaObject::Call call, ushort offset, ushort index,
|
||||||
|
int nargs, int* types, void* args[], QSemaphore* semaphore = nullptr )
|
||||||
|
{
|
||||||
|
const auto callFunction = object->metaObject()->d.static_metacall;
|
||||||
|
|
||||||
|
auto event = new MetaCallEvent( call, callFunction,
|
||||||
|
offset, index, nargs, types, args, semaphore );
|
||||||
|
|
||||||
|
QCoreApplication::postEvent( object, event );
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaMethod qskMetaMethod( const QObject* object, const char* methodName )
|
||||||
|
{
|
||||||
|
return object ? qskMetaMethod( object->metaObject(), methodName ) : QMetaMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaMethod qskMetaMethod( const QMetaObject* metaObject, const char* methodName )
|
||||||
|
{
|
||||||
|
if ( metaObject == nullptr || methodName == nullptr )
|
||||||
|
return QMetaMethod();
|
||||||
|
|
||||||
|
constexpr char signalIndicator = '0' + QSIGNAL_CODE;
|
||||||
|
constexpr char slotIndicator = '0' + QSLOT_CODE;
|
||||||
|
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
if( methodName[0] == signalIndicator )
|
||||||
|
{
|
||||||
|
auto signature = QMetaObject::normalizedSignature( methodName + 1 );
|
||||||
|
index = metaObject->indexOfSignal( signature );
|
||||||
|
}
|
||||||
|
else if ( methodName[0] == slotIndicator )
|
||||||
|
{
|
||||||
|
auto signature = QMetaObject::normalizedSignature( methodName + 1 );
|
||||||
|
index = metaObject->indexOfSlot( signature );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto signature = QMetaObject::normalizedSignature( methodName );
|
||||||
|
index = metaObject->indexOfMethod( signature );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( index >= 0 ) ? metaObject->method( index ) : QMetaMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaMethod qskNotifySignal( const QObject* object, const char* propertyName )
|
||||||
|
{
|
||||||
|
return object ? qskNotifySignal( object->metaObject(), propertyName ) : QMetaMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaMethod qskNotifySignal( const QMetaObject* metaObject, const char* propertyName )
|
||||||
|
{
|
||||||
|
if ( metaObject == nullptr || propertyName == nullptr )
|
||||||
|
return QMetaMethod();
|
||||||
|
|
||||||
|
const int propertyIndex = metaObject->indexOfProperty( propertyName );
|
||||||
|
if ( propertyIndex )
|
||||||
|
{
|
||||||
|
const auto property = metaObject->property( propertyIndex );
|
||||||
|
return property.notifySignal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QMetaMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qskInvokeMetaCall( QObject* object,
|
||||||
|
const QMetaObject* metaObject, QMetaObject::Call call,
|
||||||
|
int offset, int index, void* argv[], Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
QPointer< QObject > receiver( object );
|
||||||
|
|
||||||
int invokeType = connectionType & 0x3;
|
int invokeType = connectionType & 0x3;
|
||||||
|
|
||||||
if ( invokeType == Qt::AutoConnection )
|
if ( invokeType == Qt::AutoConnection )
|
||||||
{
|
{
|
||||||
invokeType = ( object->thread() != QThread::currentThread() )
|
invokeType = ( object && object->thread() != QThread::currentThread() )
|
||||||
? Qt::QueuedConnection : Qt::DirectConnection;
|
? Qt::QueuedConnection : Qt::DirectConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
switch( invokeType )
|
||||||
if ( invokeType != Qt::DirectConnection )
|
|
||||||
return; // TODO ...
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( propertyIndex >= 0 && object->metaObject() == metaObject )
|
|
||||||
{
|
{
|
||||||
int status = -1;
|
case Qt::DirectConnection:
|
||||||
int flags = 0;
|
{
|
||||||
void* argv[] = { args[1], nullptr, &status, &flags };
|
if ( receiver.isNull() )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// do we really always need an object, what about Q_GADGET ???
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
QMetaObject::metacall( object,
|
/*
|
||||||
QMetaObject::WriteProperty, propertyIndex, argv );
|
QMetaObject::metacall seems to be made for situations we don't have.
|
||||||
|
Need to dive deeper into the Qt code to be 100% sure TODO ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
metaObject->d.static_metacall( receiver, call, index, argv );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::BlockingQueuedConnection:
|
||||||
|
{
|
||||||
|
if ( receiver.isNull()
|
||||||
|
|| ( receiver->thread() == QThread::currentThread() ) )
|
||||||
|
{
|
||||||
|
// We would end up in a deadlock, better do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSemaphore semaphore;
|
||||||
|
|
||||||
|
qskInvokeMetaCallQueued( receiver, call, offset, index,
|
||||||
|
0, nullptr, argv, &semaphore );
|
||||||
|
|
||||||
|
semaphore.acquire();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Qt::QueuedConnection:
|
||||||
|
{
|
||||||
|
if ( receiver == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
int* types = nullptr;
|
||||||
|
void** arguments = nullptr;
|
||||||
|
int argc = 0;
|
||||||
|
|
||||||
|
if ( call == QMetaObject::InvokeMetaMethod )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// should be doable without QMetaMethod. TODO ...
|
||||||
|
const auto method = metaObject->method( offset + index );
|
||||||
|
#endif
|
||||||
|
argc = method.parameterCount() + 1;
|
||||||
|
|
||||||
|
types = static_cast< int* >( malloc( argc * sizeof( int ) ) );
|
||||||
|
arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) );
|
||||||
|
|
||||||
|
/*
|
||||||
|
The first one is the return type, one that is always
|
||||||
|
invalid for Queued Connections.
|
||||||
|
*/
|
||||||
|
|
||||||
|
types[0] = QMetaType::UnknownType;
|
||||||
|
arguments[0] = nullptr;
|
||||||
|
|
||||||
|
for ( int i = 1; i < argc; i++ )
|
||||||
|
{
|
||||||
|
if ( argv[i] == nullptr )
|
||||||
|
{
|
||||||
|
Q_ASSERT( argv[i] != nullptr );
|
||||||
|
receiver = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
types[i] = method.parameterType( i - 1 );
|
||||||
|
arguments[i] = QMetaType::create( types[i], argv[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// should be doable without QMetaMethod. TODO ...
|
||||||
|
const auto property = metaObject->property( offset + index );
|
||||||
|
|
||||||
|
argc = 1;
|
||||||
|
|
||||||
|
types = static_cast< int* >( malloc( argc * sizeof( int ) ) );
|
||||||
|
arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) );
|
||||||
|
|
||||||
|
types[0] = property.userType();
|
||||||
|
arguments[0] = QMetaType::create( types[0], argv[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( receiver.isNull() )
|
||||||
|
{
|
||||||
|
// object might have died in the meantime
|
||||||
|
free( types );
|
||||||
|
free( arguments );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qskInvokeMetaCallQueued( object, call,
|
||||||
|
offset, index, argc, types, arguments );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void qskInvokeMetaPropertyWrite( QObject* context,
|
||||||
|
const QMetaProperty& property, void* args[], Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
qskInvokeMetaPropertyWrite( context, property.enclosingMetaObject(),
|
||||||
|
property.propertyIndex(), args, connectionType );
|
||||||
|
}
|
||||||
|
|
||||||
|
void qskInvokeMetaPropertyWrite( QObject* context,
|
||||||
|
const QMetaObject* metaObject, int propertyIndex,
|
||||||
|
void* args[], Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
// check for is writable ???
|
||||||
|
|
||||||
|
if ( metaObject && ( propertyIndex >= 0 )
|
||||||
|
&& ( propertyIndex < metaObject->propertyCount() ) )
|
||||||
|
{
|
||||||
|
const auto offset = metaObject->propertyOffset();
|
||||||
|
const auto index = propertyIndex - offset;
|
||||||
|
|
||||||
|
qskInvokeMetaCall( context, metaObject, QMetaObject::WriteProperty,
|
||||||
|
offset, index, args + 1, connectionType );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void qskInvokeMetaMethod( QObject* object,
|
||||||
|
const QMetaMethod& method, void* args[],
|
||||||
|
Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
qskInvokeMetaMethod( object, method.enclosingMetaObject(),
|
||||||
|
method.methodIndex(), args, connectionType );
|
||||||
|
}
|
||||||
|
|
||||||
|
void qskInvokeMetaMethod( QObject* object,
|
||||||
|
const QMetaObject* metaObject, int methodIndex, void* argv[],
|
||||||
|
Qt::ConnectionType connectionType )
|
||||||
|
{
|
||||||
|
if ( metaObject && ( methodIndex >= 0 )
|
||||||
|
&& ( methodIndex < metaObject->methodCount() ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto offset = metaObject->methodOffset();
|
||||||
|
const auto index = methodIndex - offset;
|
||||||
|
|
||||||
|
qskInvokeMetaCall( object, metaObject, QMetaObject::InvokeMetaMethod,
|
||||||
|
offset, index, argv, connectionType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,12 +318,12 @@ QskMetaInvokable::QskMetaInvokable( const QMetaMethod& method ):
|
||||||
}
|
}
|
||||||
|
|
||||||
QskMetaInvokable::QskMetaInvokable( const QObject* object, const char* methodName ):
|
QskMetaInvokable::QskMetaInvokable( const QObject* object, const char* methodName ):
|
||||||
QskMetaInvokable( QskMetaMethod::method( object, methodName ) )
|
QskMetaInvokable( qskMetaMethod( object, methodName ) )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QskMetaInvokable::QskMetaInvokable( const QMetaObject* metaObject, const char* methodName ):
|
QskMetaInvokable::QskMetaInvokable( const QMetaObject* metaObject, const char* methodName ):
|
||||||
QskMetaInvokable( QskMetaMethod::method( metaObject, methodName ) )
|
QskMetaInvokable( qskMetaMethod( metaObject, methodName ) )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,14 +600,14 @@ void QskMetaInvokable::invoke( QObject* object, void* args[],
|
||||||
{
|
{
|
||||||
case MetaMethod:
|
case MetaMethod:
|
||||||
{
|
{
|
||||||
QskMetaMethod::invoke( object, m_metaData.metaObject,
|
qskInvokeMetaMethod( object, m_metaData.metaObject,
|
||||||
m_metaData.index, args, connectionType );
|
m_metaData.index, args, connectionType );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MetaProperty:
|
case MetaProperty:
|
||||||
{
|
{
|
||||||
qskInvokeSetProperty( object,
|
qskInvokeMetaPropertyWrite( object,
|
||||||
m_metaData.metaObject, m_metaData.index,
|
m_metaData.metaObject, m_metaData.index,
|
||||||
args, connectionType );
|
args, connectionType );
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,30 @@ inline QskMetaInvokable::Type QskMetaInvokable::type() const
|
||||||
return static_cast< Type >( m_type );
|
return static_cast< Type >( m_type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSK_EXPORT QMetaMethod qskMetaMethod( const QMetaObject*, const char* methodName );
|
||||||
|
QSK_EXPORT QMetaMethod qskMetaMethod( const QObject*, const char* methodName );
|
||||||
|
|
||||||
|
QSK_EXPORT void qskInvokeMetaMethod(
|
||||||
|
QObject*, const QMetaObject*, int methodIndex, void* args[],
|
||||||
|
Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
|
QSK_EXPORT void qskInvokeMetaMethod(
|
||||||
|
QObject*, const QMetaMethod&, void* args[],
|
||||||
|
Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
|
QSK_EXPORT void qskInvokeMetaPropertyWrite(
|
||||||
|
QObject*, const QMetaObject*, int propertyIndex,
|
||||||
|
void* args[], Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
|
QSK_EXPORT void qskInvokeMetaPropertyWrite(
|
||||||
|
const QObject* object, const QMetaProperty&,
|
||||||
|
void* args[], Qt::ConnectionType = Qt::AutoConnection );
|
||||||
|
|
||||||
|
|
||||||
|
QSK_EXPORT QMetaMethod qskNotifySignal( const QMetaObject*, const char* propertyName );
|
||||||
|
QSK_EXPORT QMetaMethod qskNotifySignal( const QObject*, const char* propertyName );
|
||||||
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE( QskMetaInvokable )
|
Q_DECLARE_METATYPE( QskMetaInvokable )
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,205 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
||||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#include "QskMetaMethod.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QSemaphore>
|
|
||||||
#include <QMetaMethod>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
const int methodOffset = metaObject->methodOffset();
|
|
||||||
|
|
||||||
auto event = new QMetaCallEvent(
|
|
||||||
methodOffset, methodIndex - methodOffset,
|
|
||||||
metaObject->d.static_metacall,
|
|
||||||
sender, signalId, nargs, types, args, semaphore );
|
|
||||||
|
|
||||||
QCoreApplication::postEvent( object, event );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaMethod::invoke( QObject* object,
|
|
||||||
const QMetaMethod& method, void* args[],
|
|
||||||
Qt::ConnectionType connectionType )
|
|
||||||
{
|
|
||||||
auto metaObject = method.enclosingMetaObject();
|
|
||||||
if ( metaObject == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const int methodIndex = method.methodIndex() - metaObject->methodOffset();
|
|
||||||
invoke( object, metaObject, methodIndex, args, connectionType );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskMetaMethod::invoke( QObject* object,
|
|
||||||
const QMetaObject* metaObject, int methodIndex, void* argv[],
|
|
||||||
Qt::ConnectionType connectionType )
|
|
||||||
{
|
|
||||||
if ( ( metaObject == nullptr ) || ( methodIndex < 0 )
|
|
||||||
|| ( methodIndex >= metaObject->methodCount() ) )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointer< QObject > receiver( object );
|
|
||||||
|
|
||||||
int invokeType = connectionType & 0x3;
|
|
||||||
|
|
||||||
if ( invokeType == Qt::AutoConnection )
|
|
||||||
{
|
|
||||||
invokeType = ( object && object->thread() != QThread::currentThread() )
|
|
||||||
? Qt::QueuedConnection : Qt::DirectConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch( invokeType )
|
|
||||||
{
|
|
||||||
case Qt::DirectConnection:
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
if ( receiver.isNull() )
|
|
||||||
return; // do we really always need an object here ???
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const int index = methodIndex - metaObject->methodOffset();
|
|
||||||
|
|
||||||
if ( metaObject->d.static_metacall )
|
|
||||||
{
|
|
||||||
metaObject->d.static_metacall( receiver,
|
|
||||||
QMetaObject::InvokeMetaMethod, index, argv );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QMetaObject::metacall( receiver,
|
|
||||||
QMetaObject::InvokeMetaMethod, index, argv );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Qt::BlockingQueuedConnection:
|
|
||||||
{
|
|
||||||
if ( receiver.isNull()
|
|
||||||
|| ( receiver->thread() == QThread::currentThread() ) )
|
|
||||||
{
|
|
||||||
// We would end up in a deadlock, better do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSemaphore semaphore;
|
|
||||||
|
|
||||||
qskInvokeMethodQueued( receiver, metaObject,
|
|
||||||
methodIndex, 0, nullptr, argv, &semaphore );
|
|
||||||
|
|
||||||
semaphore.acquire();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Qt::QueuedConnection:
|
|
||||||
{
|
|
||||||
if ( receiver == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// should be doable without QMetaMethod. TODO ...
|
|
||||||
const auto method = metaObject->method( methodIndex );
|
|
||||||
#endif
|
|
||||||
const int argc = method.parameterCount() + 1;
|
|
||||||
|
|
||||||
auto types = static_cast< int* >( malloc( argc * sizeof( int ) ) );
|
|
||||||
auto arguments = static_cast< void** >( malloc( argc * sizeof( void* ) ) );
|
|
||||||
|
|
||||||
/*
|
|
||||||
The first one is the return type, one that is always
|
|
||||||
invalid for Queued Connections.
|
|
||||||
*/
|
|
||||||
|
|
||||||
types[0] = QMetaType::UnknownType;
|
|
||||||
arguments[0] = nullptr;
|
|
||||||
|
|
||||||
for ( int i = 1; i < argc; i++ )
|
|
||||||
{
|
|
||||||
if ( argv[i] == nullptr )
|
|
||||||
{
|
|
||||||
Q_ASSERT( argv[i] != nullptr );
|
|
||||||
receiver = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
types[i] = method.parameterType( i - 1 );
|
|
||||||
arguments[i] = QMetaType::create( types[i], argv[i] );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( receiver.isNull() )
|
|
||||||
{
|
|
||||||
// object might have died in the meantime
|
|
||||||
free( types );
|
|
||||||
free( arguments );
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qskInvokeMethodQueued( object,
|
|
||||||
metaObject, methodIndex, argc, types, arguments );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QMetaMethod QskMetaMethod::method(
|
|
||||||
const QMetaObject* metaObject, const char* methodName )
|
|
||||||
{
|
|
||||||
if ( metaObject == nullptr || methodName == nullptr )
|
|
||||||
return QMetaMethod();
|
|
||||||
|
|
||||||
constexpr char signalIndicator = '0' + QSIGNAL_CODE;
|
|
||||||
constexpr char slotIndicator = '0' + QSLOT_CODE;
|
|
||||||
|
|
||||||
int index = -1;
|
|
||||||
|
|
||||||
if( methodName[0] == signalIndicator )
|
|
||||||
{
|
|
||||||
auto signature = QMetaObject::normalizedSignature( methodName + 1 );
|
|
||||||
index = metaObject->indexOfSignal( signature );
|
|
||||||
}
|
|
||||||
else if ( methodName[0] == slotIndicator )
|
|
||||||
{
|
|
||||||
auto signature = QMetaObject::normalizedSignature( methodName + 1 );
|
|
||||||
index = metaObject->indexOfSlot( signature );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto signature = QMetaObject::normalizedSignature( methodName );
|
|
||||||
index = metaObject->indexOfMethod( signature );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( index >= 0 ) ? metaObject->method( index ) : QMetaMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMetaMethod QskMetaMethod::notifySignal(
|
|
||||||
const QMetaObject* metaObject, const char* propertyName )
|
|
||||||
{
|
|
||||||
if ( metaObject == nullptr || propertyName == nullptr )
|
|
||||||
return QMetaMethod();
|
|
||||||
|
|
||||||
const int propertyIndex = metaObject->indexOfProperty( propertyName );
|
|
||||||
if ( propertyIndex )
|
|
||||||
{
|
|
||||||
const auto property = metaObject->property( propertyIndex );
|
|
||||||
return property.notifySignal();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QMetaMethod();
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
||||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef QSK_META_METHOD_H
|
|
||||||
#define QSK_META_FUNCTION_H 1
|
|
||||||
|
|
||||||
#include "QskGlobal.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMetaMethod>
|
|
||||||
|
|
||||||
class QObject;
|
|
||||||
class QMetaMethod;
|
|
||||||
class QMetaObject;
|
|
||||||
|
|
||||||
namespace QskMetaMethod
|
|
||||||
{
|
|
||||||
QSK_EXPORT void invoke(
|
|
||||||
QObject* object, const QMetaMethod&, void* args[],
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
QSK_EXPORT void invoke(
|
|
||||||
QObject*, const QMetaObject*, int methodIndex, void* args[],
|
|
||||||
Qt::ConnectionType = Qt::AutoConnection );
|
|
||||||
|
|
||||||
QSK_EXPORT QMetaMethod method( const QMetaObject*, const char* methodName );
|
|
||||||
QSK_EXPORT QMetaMethod method( const QObject*, const char* methodName );
|
|
||||||
|
|
||||||
QSK_EXPORT QMetaMethod notifySignal( const QMetaObject*, const char* propertyName );
|
|
||||||
QSK_EXPORT QMetaMethod notifySignal( const QObject*, const char* propertyName );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QMetaMethod QskMetaMethod::method(
|
|
||||||
const QObject* object, const char* methodName )
|
|
||||||
{
|
|
||||||
return object ? method( object->metaObject(), methodName ) : QMetaMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QMetaMethod QskMetaMethod::notifySignal(
|
|
||||||
const QObject* object, const char* propertyName )
|
|
||||||
{
|
|
||||||
return object ? notifySignal( object->metaObject(), propertyName ) : QMetaMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -40,11 +40,9 @@ HEADERS += \
|
||||||
common/QskGlobal.h \
|
common/QskGlobal.h \
|
||||||
common/QskGradient.h \
|
common/QskGradient.h \
|
||||||
common/QskMargins.h \
|
common/QskMargins.h \
|
||||||
common/QskMetaCallback.h \
|
|
||||||
common/QskMetaFunction.h \
|
common/QskMetaFunction.h \
|
||||||
common/QskMetaFunction.hpp \
|
common/QskMetaFunction.hpp \
|
||||||
common/QskMetaInvokable.h \
|
common/QskMetaInvokable.h \
|
||||||
common/QskMetaMethod.h \
|
|
||||||
common/QskModule.h \
|
common/QskModule.h \
|
||||||
common/QskNamespace.h \
|
common/QskNamespace.h \
|
||||||
common/QskObjectCounter.h \
|
common/QskObjectCounter.h \
|
||||||
|
@ -61,10 +59,8 @@ SOURCES += \
|
||||||
common/QskFunctions.cpp \
|
common/QskFunctions.cpp \
|
||||||
common/QskGradient.cpp \
|
common/QskGradient.cpp \
|
||||||
common/QskMargins.cpp \
|
common/QskMargins.cpp \
|
||||||
common/QskMetaCallback.cpp \
|
|
||||||
common/QskMetaFunction.cpp \
|
common/QskMetaFunction.cpp \
|
||||||
common/QskMetaInvokable.cpp \
|
common/QskMetaInvokable.cpp \
|
||||||
common/QskMetaMethod.cpp \
|
|
||||||
common/QskModule.cpp \
|
common/QskModule.cpp \
|
||||||
common/QskObjectCounter.cpp \
|
common/QskObjectCounter.cpp \
|
||||||
common/QskSizePolicy.cpp \
|
common/QskSizePolicy.cpp \
|
||||||
|
|
Loading…
Reference in New Issue