QObject: allow connecting to functors with a receiver object
Up to now, it was only possible to connect to functors in a direct way, without being capable of using Qt::ConnectionType. This patch allows for specifying a receiver for Functors and function pointers, hence making it possible to specify effectively the connection type. To do this properly, it was needed to add an enum in FunctionPointer representing whether the considered function is a member function or not, to reduce ambiguity upon overloaded calls. Moreover, now senders are checked for the existence of a slot obj as well. This way, should the context be freed, the slot obj and the functor contained in it will be freed as well. On a side note, connecting to a static slot (like QCoreApplication::quit) specifying the receiver object is now compiling. Change-Id: I46474099413b1dc6ca4db9934191d469baeef070 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
ae577e6b8f
commit
76b06f993e
@ -472,6 +472,21 @@ if (isSignalConnected(valueChangedSignal)) {
|
|||||||
}
|
}
|
||||||
//! [49]
|
//! [49]
|
||||||
|
|
||||||
|
//! [50]
|
||||||
|
void someFunction();
|
||||||
|
QPushButton *button = new QPushButton;
|
||||||
|
QObject::connect(button, &QPushButton::clicked, this, someFunction, Qt::QueuedConnection);
|
||||||
|
//! [50]
|
||||||
|
|
||||||
|
//! [51]
|
||||||
|
QByteArray page = ...;
|
||||||
|
QTcpSocket *socket = new QTcpSocket;
|
||||||
|
socket->connectToHost("qt-project.org", 80);
|
||||||
|
QObject::connect(socket, &QTcpSocket::connected, this, [=] () {
|
||||||
|
socket->write("GET " + page + "\r\n");
|
||||||
|
}, Qt::AutoConnection);
|
||||||
|
//! [51]
|
||||||
|
|
||||||
//! [meta data]
|
//! [meta data]
|
||||||
//: This is a comment for the translator.
|
//: This is a comment for the translator.
|
||||||
//= qtn_foo_bar
|
//= qtn_foo_bar
|
||||||
|
@ -854,9 +854,23 @@ QObject::~QObject()
|
|||||||
senderLists->dirty = true;
|
senderLists->dirty = true;
|
||||||
|
|
||||||
int signal_index = node->signal_index;
|
int signal_index = node->signal_index;
|
||||||
|
|
||||||
|
QtPrivate::QSlotObjectBase *slotObj = Q_NULLPTR;
|
||||||
|
if (node->isSlotObject) {
|
||||||
|
slotObj = node->slotObj;
|
||||||
|
node->isSlotObject = false;
|
||||||
|
}
|
||||||
|
|
||||||
node = node->next;
|
node = node->next;
|
||||||
if (needToUnlock)
|
if (needToUnlock)
|
||||||
m->unlock();
|
m->unlock();
|
||||||
|
|
||||||
|
if (slotObj) {
|
||||||
|
locker.unlock();
|
||||||
|
slotObj->destroyIfLastRef();
|
||||||
|
locker.relock();
|
||||||
|
}
|
||||||
|
|
||||||
sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index));
|
sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4272,6 +4286,43 @@ void qDeleteInEventHandler(QObject *o)
|
|||||||
must not have an overloaded or templated operator().
|
must not have an overloaded or templated operator().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type)
|
||||||
|
|
||||||
|
\threadsafe
|
||||||
|
\overload connect()
|
||||||
|
|
||||||
|
\since 5.2
|
||||||
|
|
||||||
|
Creates a connection of a given \a type from \a signal in
|
||||||
|
\a sender object to \a functor to be placed in a specific event
|
||||||
|
loop of \a context, and returns a handle to the connection
|
||||||
|
|
||||||
|
The signal must be a function declared as a signal in the header.
|
||||||
|
The slot function can be any function or functor that can be connected
|
||||||
|
to the signal.
|
||||||
|
A function can be connected to a given signal if the signal as at
|
||||||
|
least as many argument as the slot. A functor can be connected to a signal
|
||||||
|
if they have exactly the same number of arguments. There must exist implicit
|
||||||
|
conversion between the types of the corresponding arguments in the
|
||||||
|
signal and the slot.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
\snippet code/src_corelib_kernel_qobject.cpp 50
|
||||||
|
|
||||||
|
If your compiler support C++11 lambda expressions, you can use them:
|
||||||
|
|
||||||
|
\snippet code/src_corelib_kernel_qobject.cpp 51
|
||||||
|
|
||||||
|
The connection will automatically disconnect if the sender or the context
|
||||||
|
is destroyed.
|
||||||
|
|
||||||
|
\note If the compiler does not support C++11 variadic templates, the number
|
||||||
|
of arguments in the signal or slot are limited to 6, and the functor object
|
||||||
|
must not have an overloaded or templated operator().
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
|
|
||||||
|
@ -208,6 +208,7 @@ public:
|
|||||||
#ifdef Q_QDOC
|
#ifdef Q_QDOC
|
||||||
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type);
|
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type);
|
||||||
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
|
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
|
||||||
|
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type);
|
||||||
#else
|
#else
|
||||||
//Connect a signal to a pointer to qobject member function
|
//Connect a signal to a pointer to qobject member function
|
||||||
template <typename Func1, typename Func2>
|
template <typename Func1, typename Func2>
|
||||||
@ -244,6 +245,16 @@ public:
|
|||||||
template <typename Func1, typename Func2>
|
template <typename Func1, typename Func2>
|
||||||
static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::Type
|
static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::Type
|
||||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
|
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
|
||||||
|
{
|
||||||
|
return connect(sender, signal, sender, slot, Qt::DirectConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect to a function pointer (not a member)
|
||||||
|
template <typename Func1, typename Func2>
|
||||||
|
static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
|
||||||
|
!QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::Type
|
||||||
|
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
|
||||||
|
Qt::ConnectionType type = Qt::AutoConnection)
|
||||||
{
|
{
|
||||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||||
typedef QtPrivate::FunctionPointer<Func2> SlotType;
|
typedef QtPrivate::FunctionPointer<Func2> SlotType;
|
||||||
@ -259,11 +270,15 @@ public:
|
|||||||
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
|
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
|
||||||
"Return type of the slot is not compatible with the return type of the signal.");
|
"Return type of the slot is not compatible with the return type of the signal.");
|
||||||
|
|
||||||
return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0,
|
const int *types = 0;
|
||||||
|
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
|
||||||
|
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||||
|
|
||||||
|
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, 0,
|
||||||
new QtPrivate::QStaticSlotObject<Func2,
|
new QtPrivate::QStaticSlotObject<Func2,
|
||||||
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
|
||||||
typename SignalType::ReturnType>(slot),
|
typename SignalType::ReturnType>(slot),
|
||||||
Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
|
type, types, &SignalType::Object::staticMetaObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
//connect to a functor
|
//connect to a functor
|
||||||
@ -271,6 +286,15 @@ public:
|
|||||||
static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
|
static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
|
||||||
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
|
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
|
||||||
{
|
{
|
||||||
|
return connect(sender, signal, sender, slot, Qt::DirectConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
//connect to a functor, with a "context" object defining in which event loop is going to be executed
|
||||||
|
template <typename Func1, typename Func2>
|
||||||
|
static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
|
||||||
|
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
|
||||||
|
Qt::ConnectionType type = Qt::AutoConnection)
|
||||||
|
{
|
||||||
#if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES)
|
#if defined (Q_COMPILER_DECLTYPE) && defined (Q_COMPILER_VARIADIC_TEMPLATES)
|
||||||
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
typedef QtPrivate::FunctionPointer<Func1> SignalType;
|
||||||
const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
|
const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
|
||||||
@ -292,9 +316,10 @@ public:
|
|||||||
C++11 variadic templates
|
C++11 variadic templates
|
||||||
*/
|
*/
|
||||||
#ifndef Q_COMPILER_DECLTYPE //Workaround the lack of decltype using another function as indirection
|
#ifndef Q_COMPILER_DECLTYPE //Workaround the lack of decltype using another function as indirection
|
||||||
return connect_functor(sender, signal, slot, &Func2::operator()); }
|
return connect_functor(sender, signal, context, slot, &Func2::operator(), type); }
|
||||||
template <typename Func1, typename Func2, typename Func2Operator>
|
template <typename Func1, typename Func2, typename Func2Operator>
|
||||||
static inline QMetaObject::Connection connect_functor(const QObject *sender, Func1 signal, Func2 slot, Func2Operator) {
|
static inline QMetaObject::Connection connect_functor(const QObject *sender, Func1 signal, const QObject *context,
|
||||||
|
Func2 slot, Func2Operator, Qt::ConnectionType type) {
|
||||||
typedef QtPrivate::FunctionPointer<Func2Operator> SlotType ;
|
typedef QtPrivate::FunctionPointer<Func2Operator> SlotType ;
|
||||||
#else
|
#else
|
||||||
typedef QtPrivate::FunctionPointer<decltype(&Func2::operator())> SlotType ;
|
typedef QtPrivate::FunctionPointer<decltype(&Func2::operator())> SlotType ;
|
||||||
@ -315,11 +340,15 @@ public:
|
|||||||
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
|
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
|
||||||
"No Q_OBJECT in the class with the signal");
|
"No Q_OBJECT in the class with the signal");
|
||||||
|
|
||||||
return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0,
|
const int *types = 0;
|
||||||
|
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
|
||||||
|
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
|
||||||
|
|
||||||
|
return connectImpl(sender, reinterpret_cast<void **>(&signal), context, 0,
|
||||||
new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
|
new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
|
||||||
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
|
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
|
||||||
typename SignalType::ReturnType>(slot),
|
typename SignalType::ReturnType>(slot),
|
||||||
Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
|
type, types, &SignalType::Object::staticMetaObject);
|
||||||
}
|
}
|
||||||
#endif //Q_QDOC
|
#endif //Q_QDOC
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ namespace QtPrivate {
|
|||||||
its call function is the same as the FunctionPointer::call function.
|
its call function is the same as the FunctionPointer::call function.
|
||||||
*/
|
*/
|
||||||
#ifndef Q_COMPILER_VARIADIC_TEMPLATES
|
#ifndef Q_COMPILER_VARIADIC_TEMPLATES
|
||||||
template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1}; };
|
template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
|
||||||
//Pointers to member functions
|
//Pointers to member functions
|
||||||
template<class Obj, typename Ret> struct FunctionPointer<Ret (Obj::*) ()>
|
template<class Obj, typename Ret> struct FunctionPointer<Ret (Obj::*) ()>
|
||||||
{
|
{
|
||||||
@ -137,7 +137,7 @@ namespace QtPrivate {
|
|||||||
typedef void Arguments;
|
typedef void Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) ();
|
typedef Ret (Obj::*Function) ();
|
||||||
enum {ArgumentCount = 0};
|
enum {ArgumentCount = 0, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); }
|
static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); }
|
||||||
};
|
};
|
||||||
@ -147,7 +147,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, void> Arguments;
|
typedef List<Arg1, void> Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1);
|
typedef Ret (Obj::*Function) (Arg1);
|
||||||
enum {ArgumentCount = 1};
|
enum {ArgumentCount = 1, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]);
|
(o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]);
|
||||||
@ -159,7 +159,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, void> > Arguments;
|
typedef List<Arg1, List<Arg2, void> > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2);
|
typedef Ret (Obj::*Function) (Arg1, Arg2);
|
||||||
enum {ArgumentCount = 2};
|
enum {ArgumentCount = 2, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -172,7 +172,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3);
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3);
|
||||||
enum {ArgumentCount = 3};
|
enum {ArgumentCount = 3, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -186,7 +186,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4);
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4);
|
||||||
enum {ArgumentCount = 4};
|
enum {ArgumentCount = 4, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -201,7 +201,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5);
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5);
|
||||||
enum {ArgumentCount = 5};
|
enum {ArgumentCount = 5, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -218,7 +218,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
|
||||||
enum {ArgumentCount = 6};
|
enum {ArgumentCount = 6, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -237,7 +237,7 @@ namespace QtPrivate {
|
|||||||
typedef void Arguments;
|
typedef void Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) () const;
|
typedef Ret (Obj::*Function) () const;
|
||||||
enum {ArgumentCount = 0};
|
enum {ArgumentCount = 0, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); }
|
static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); }
|
||||||
};
|
};
|
||||||
@ -247,7 +247,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, void> Arguments;
|
typedef List<Arg1, void> Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1) const;
|
typedef Ret (Obj::*Function) (Arg1) const;
|
||||||
enum {ArgumentCount = 1};
|
enum {ArgumentCount = 1, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]);
|
(o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]);
|
||||||
@ -259,7 +259,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, void> > Arguments;
|
typedef List<Arg1, List<Arg2, void> > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2) const;
|
typedef Ret (Obj::*Function) (Arg1, Arg2) const;
|
||||||
enum {ArgumentCount = 2};
|
enum {ArgumentCount = 2, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -272,7 +272,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3) const;
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3) const;
|
||||||
enum {ArgumentCount = 3};
|
enum {ArgumentCount = 3, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -286,7 +286,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4) const;
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4) const;
|
||||||
enum {ArgumentCount = 4};
|
enum {ArgumentCount = 4, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -301,7 +301,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5) const;
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5) const;
|
||||||
enum {ArgumentCount = 5};
|
enum {ArgumentCount = 5, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -318,7 +318,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const;
|
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const;
|
||||||
enum {ArgumentCount = 6};
|
enum {ArgumentCount = 6, IsPointerToMemberFunction = true};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
(o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -336,7 +336,7 @@ namespace QtPrivate {
|
|||||||
typedef void Arguments;
|
typedef void Arguments;
|
||||||
typedef Ret (*Function) ();
|
typedef Ret (*Function) ();
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
enum {ArgumentCount = 0};
|
enum {ArgumentCount = 0, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg) { f(), ApplyReturnValue<R>(arg[0]); }
|
static void call(Function f, void *, void **arg) { f(), ApplyReturnValue<R>(arg[0]); }
|
||||||
};
|
};
|
||||||
@ -345,7 +345,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, void> Arguments;
|
typedef List<Arg1, void> Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Arg1);
|
typedef Ret (*Function) (Arg1);
|
||||||
enum {ArgumentCount = 1};
|
enum {ArgumentCount = 1, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg)
|
static void call(Function f, void *, void **arg)
|
||||||
{ f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1])), ApplyReturnValue<R>(arg[0]); }
|
{ f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1])), ApplyReturnValue<R>(arg[0]); }
|
||||||
@ -355,7 +355,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, void> > Arguments;
|
typedef List<Arg1, List<Arg2, void> > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Arg1, Arg2);
|
typedef Ret (*Function) (Arg1, Arg2);
|
||||||
enum {ArgumentCount = 2};
|
enum {ArgumentCount = 2, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg) {
|
static void call(Function f, void *, void **arg) {
|
||||||
f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -366,7 +366,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Arg1, Arg2, Arg3);
|
typedef Ret (*Function) (Arg1, Arg2, Arg3);
|
||||||
enum {ArgumentCount = 3};
|
enum {ArgumentCount = 3, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg) {
|
static void call(Function f, void *, void **arg) {
|
||||||
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -379,7 +379,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4);
|
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4);
|
||||||
enum {ArgumentCount = 4};
|
enum {ArgumentCount = 4, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg) {
|
static void call(Function f, void *, void **arg) {
|
||||||
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -394,7 +394,7 @@ namespace QtPrivate {
|
|||||||
List<Arg4, List<Arg5, void > > > > > Arguments;
|
List<Arg4, List<Arg5, void > > > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5);
|
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5);
|
||||||
enum {ArgumentCount = 5};
|
enum {ArgumentCount = 5, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg) {
|
static void call(Function f, void *, void **arg) {
|
||||||
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -409,7 +409,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments;
|
typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
|
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
|
||||||
enum {ArgumentCount = 6};
|
enum {ArgumentCount = 6, IsPointerToMemberFunction = false};
|
||||||
template <typename Args, typename R>
|
template <typename Args, typename R>
|
||||||
static void call(Function f, void *, void **arg) {
|
static void call(Function f, void *, void **arg) {
|
||||||
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]),
|
||||||
@ -493,7 +493,7 @@ namespace QtPrivate {
|
|||||||
template <int N> struct Indexes
|
template <int N> struct Indexes
|
||||||
{ typedef typename IndexesAppend<typename Indexes<N - 1>::Value, N - 1>::Value Value; };
|
{ typedef typename IndexesAppend<typename Indexes<N - 1>::Value, N - 1>::Value Value; };
|
||||||
template <> struct Indexes<0> { typedef IndexesList<> Value; };
|
template <> struct Indexes<0> { typedef IndexesList<> Value; };
|
||||||
template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1}; };
|
template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; };
|
||||||
|
|
||||||
template <typename, typename, typename, typename> struct FunctorCall;
|
template <typename, typename, typename, typename> struct FunctorCall;
|
||||||
template <int... II, typename... SignalArgs, typename R, typename Function>
|
template <int... II, typename... SignalArgs, typename R, typename Function>
|
||||||
@ -521,7 +521,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Args...> Arguments;
|
typedef List<Args...> Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Args...);
|
typedef Ret (Obj::*Function) (Args...);
|
||||||
enum {ArgumentCount = sizeof...(Args)};
|
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
|
||||||
template <typename SignalArgs, typename R>
|
template <typename SignalArgs, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
|
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
|
||||||
@ -533,7 +533,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Args...> Arguments;
|
typedef List<Args...> Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (Obj::*Function) (Args...) const;
|
typedef Ret (Obj::*Function) (Args...) const;
|
||||||
enum {ArgumentCount = sizeof...(Args)};
|
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
|
||||||
template <typename SignalArgs, typename R>
|
template <typename SignalArgs, typename R>
|
||||||
static void call(Function f, Obj *o, void **arg) {
|
static void call(Function f, Obj *o, void **arg) {
|
||||||
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
|
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
|
||||||
@ -545,7 +545,7 @@ namespace QtPrivate {
|
|||||||
typedef List<Args...> Arguments;
|
typedef List<Args...> Arguments;
|
||||||
typedef Ret ReturnType;
|
typedef Ret ReturnType;
|
||||||
typedef Ret (*Function) (Args...);
|
typedef Ret (*Function) (Args...);
|
||||||
enum {ArgumentCount = sizeof...(Args)};
|
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
|
||||||
template <typename SignalArgs, typename R>
|
template <typename SignalArgs, typename R>
|
||||||
static void call(Function f, void *, void **arg) {
|
static void call(Function f, void *, void **arg) {
|
||||||
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
|
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
|
||||||
|
@ -90,7 +90,7 @@ private slots:
|
|||||||
void thread();
|
void thread();
|
||||||
void thread0();
|
void thread0();
|
||||||
void moveToThread();
|
void moveToThread();
|
||||||
void sender();
|
void senderTest();
|
||||||
void declareInterface();
|
void declareInterface();
|
||||||
void qpointerResetBeforeDestroyedSignal();
|
void qpointerResetBeforeDestroyedSignal();
|
||||||
void testUserData();
|
void testUserData();
|
||||||
@ -144,7 +144,11 @@ private slots:
|
|||||||
void connectPrivateSlots();
|
void connectPrivateSlots();
|
||||||
void connectFunctorArgDifference();
|
void connectFunctorArgDifference();
|
||||||
void connectFunctorOverloads();
|
void connectFunctorOverloads();
|
||||||
|
void connectFunctorQueued();
|
||||||
|
void connectFunctorWithContext();
|
||||||
|
void connectStaticSlotWithObject();
|
||||||
void disconnectDoesNotLeakFunctor();
|
void disconnectDoesNotLeakFunctor();
|
||||||
|
void contextDoesNotLeakFunctor();
|
||||||
void connectBase();
|
void connectBase();
|
||||||
void qmlConnect();
|
void qmlConnect();
|
||||||
};
|
};
|
||||||
@ -2152,7 +2156,7 @@ signals:
|
|||||||
void theSignal();
|
void theSignal();
|
||||||
};
|
};
|
||||||
|
|
||||||
void tst_QObject::sender()
|
void tst_QObject::senderTest()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
SuperObject sender;
|
SuperObject sender;
|
||||||
@ -5602,6 +5606,129 @@ void tst_QObject::connectFunctorArgDifference()
|
|||||||
QVERIFY(true);
|
QVERIFY(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ContextObject : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
void compareSender(QObject *s) { QCOMPARE(s, sender()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SlotArgFunctor
|
||||||
|
{
|
||||||
|
SlotArgFunctor(int *s) : status(s), context(Q_NULLPTR), sender(Q_NULLPTR) {}
|
||||||
|
SlotArgFunctor(ContextObject *context, QObject *sender, int *s) : status(s), context(context), sender(sender) {}
|
||||||
|
void operator()() { *status = 2; if (context) context->compareSender(sender); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int *status;
|
||||||
|
ContextObject *context;
|
||||||
|
QObject *sender;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QObject::connectFunctorQueued()
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
SenderObject obj;
|
||||||
|
QEventLoop e;
|
||||||
|
|
||||||
|
connect(&obj, &SenderObject::signal1, this, SlotArgFunctor(&status), Qt::QueuedConnection);
|
||||||
|
connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
obj.emitSignal1();
|
||||||
|
QCOMPARE(status, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(status, 2);
|
||||||
|
|
||||||
|
#if defined(Q_COMPILER_LAMBDA)
|
||||||
|
status = 1;
|
||||||
|
connect(&obj, &SenderObject::signal1, this, [&status] { status = 2; }, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
obj.emitSignal1();
|
||||||
|
QCOMPARE(status, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(status, 2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QObject::connectFunctorWithContext()
|
||||||
|
{
|
||||||
|
int status = 1;
|
||||||
|
SenderObject obj;
|
||||||
|
QMetaObject::Connection handle;
|
||||||
|
ContextObject *context = new ContextObject;
|
||||||
|
QEventLoop e;
|
||||||
|
|
||||||
|
connect(&obj, &SenderObject::signal1, context, SlotArgFunctor(&status));
|
||||||
|
connect(&obj, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// When the context gets deleted, the connection should decay and the signal shouldn't trigger
|
||||||
|
// The connection is queued to make sure the destroyed signal propagates correctly and
|
||||||
|
// cuts the connection.
|
||||||
|
connect(context, &QObject::destroyed, &obj, &SenderObject::signal1, Qt::QueuedConnection);
|
||||||
|
context->deleteLater();
|
||||||
|
|
||||||
|
QCOMPARE(status, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(status, 1);
|
||||||
|
|
||||||
|
// Check the sender arg is set correctly in the context
|
||||||
|
context = new ContextObject;
|
||||||
|
|
||||||
|
connect(&obj, &SenderObject::signal1, context,
|
||||||
|
SlotArgFunctor(context, &obj, &status), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
obj.emitSignal1();
|
||||||
|
QCOMPARE(status, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(status, 2);
|
||||||
|
|
||||||
|
#if defined(Q_COMPILER_LAMBDA)
|
||||||
|
status = 1;
|
||||||
|
connect(&obj, &SenderObject::signal1, this, [this, &status, &obj] { status = 2; QCOMPARE(sender(), &obj); }, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
obj.emitSignal1();
|
||||||
|
QCOMPARE(status, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(status, 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Free
|
||||||
|
context->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_static_slot_checker = 1;
|
||||||
|
|
||||||
|
class StaticSlotChecker : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public Q_SLOTS:
|
||||||
|
static void staticSlot() { s_static_slot_checker = 2; }
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QObject::connectStaticSlotWithObject()
|
||||||
|
{
|
||||||
|
SenderObject sender;
|
||||||
|
StaticSlotChecker *receiver = new StaticSlotChecker;
|
||||||
|
QEventLoop e;
|
||||||
|
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1, receiver, &StaticSlotChecker::staticSlot, Qt::QueuedConnection));
|
||||||
|
connect(&sender, &SenderObject::signal1, &e, &QEventLoop::quit, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(s_static_slot_checker, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(s_static_slot_checker, 2);
|
||||||
|
|
||||||
|
s_static_slot_checker = 1;
|
||||||
|
|
||||||
|
connect(receiver, &QObject::destroyed, &sender, &SenderObject::signal1, Qt::QueuedConnection);
|
||||||
|
receiver->deleteLater();
|
||||||
|
|
||||||
|
QCOMPARE(s_static_slot_checker, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(s_static_slot_checker, 1);
|
||||||
|
}
|
||||||
|
|
||||||
struct ComplexFunctor {
|
struct ComplexFunctor {
|
||||||
ComplexFunctor(int &overload, QList<QVariant> &result) : overload(overload), result(result) {}
|
ComplexFunctor(int &overload, QList<QVariant> &result) : overload(overload), result(result) {}
|
||||||
void operator()(int a, int b) {
|
void operator()(int a, int b) {
|
||||||
@ -5773,6 +5900,23 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
|
|||||||
QCOMPARE(countedStructObjectsCount, 0);
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
}
|
}
|
||||||
QCOMPARE(countedStructObjectsCount, 0);
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
{
|
||||||
|
GetSenderObject obj;
|
||||||
|
QMetaObject::Connection c;
|
||||||
|
{
|
||||||
|
CountedStruct s(&obj);
|
||||||
|
QObject context;
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
|
||||||
|
c = connect(&obj, &GetSenderObject::aSignal, &context, s);
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(countedStructObjectsCount, 2);
|
||||||
|
QVERIFY(QObject::disconnect(c));
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
{
|
{
|
||||||
QMetaObject::Connection c1, c2;
|
QMetaObject::Connection c1, c2;
|
||||||
{
|
{
|
||||||
@ -5857,6 +6001,67 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
|
|||||||
QCOMPARE(countedStructObjectsCount, 0);
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QObject::contextDoesNotLeakFunctor()
|
||||||
|
{
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
{
|
||||||
|
QMetaObject::Connection c;
|
||||||
|
{
|
||||||
|
QEventLoop e;
|
||||||
|
ContextObject *context = new ContextObject;
|
||||||
|
SenderObject obj;
|
||||||
|
|
||||||
|
connect(&obj, &SenderObject::signal1, context, CountedStruct());
|
||||||
|
connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection);
|
||||||
|
context->deleteLater();
|
||||||
|
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
{
|
||||||
|
GetSenderObject obj;
|
||||||
|
QMetaObject::Connection c;
|
||||||
|
{
|
||||||
|
CountedStruct s(&obj);
|
||||||
|
QEventLoop e;
|
||||||
|
ContextObject *context = new ContextObject;
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
|
||||||
|
connect(&obj, &GetSenderObject::aSignal, context, s);
|
||||||
|
QCOMPARE(countedStructObjectsCount, 2);
|
||||||
|
|
||||||
|
connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection);
|
||||||
|
context->deleteLater();
|
||||||
|
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
{
|
||||||
|
#if defined(Q_COMPILER_LAMBDA)
|
||||||
|
CountedStruct s;
|
||||||
|
QEventLoop e;
|
||||||
|
ContextObject *context = new ContextObject;
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
QTimer timer;
|
||||||
|
|
||||||
|
connect(&timer, &QTimer::timeout, context, [s](){});
|
||||||
|
QCOMPARE(countedStructObjectsCount, 2);
|
||||||
|
connect(context, &QObject::destroyed, &e, &QEventLoop::quit, Qt::QueuedConnection);
|
||||||
|
context->deleteLater();
|
||||||
|
e.exec();
|
||||||
|
QCOMPARE(countedStructObjectsCount, 1);
|
||||||
|
#endif // Q_COMPILER_LAMBDA
|
||||||
|
}
|
||||||
|
QCOMPARE(countedStructObjectsCount, 0);
|
||||||
|
}
|
||||||
|
|
||||||
class SubSender : public SenderObject {
|
class SubSender : public SenderObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user