summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp15
-rw-r--r--src/corelib/kernel/qobject.cpp51
-rw-r--r--src/corelib/kernel/qobject.h41
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h52
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp209
5 files changed, 334 insertions, 34 deletions
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
index 6a2305cc85..4ecc1758ae 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
@@ -472,6 +472,21 @@ if (isSignalConnected(valueChangedSignal)) {
}
//! [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]
//: This is a comment for the translator.
//= qtn_foo_bar
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index b914ca812f..cc689657d2 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -854,9 +854,23 @@ QObject::~QObject()
senderLists->dirty = true;
int signal_index = node->signal_index;
+
+ QtPrivate::QSlotObjectBase *slotObj = Q_NULLPTR;
+ if (node->isSlotObject) {
+ slotObj = node->slotObj;
+ node->isSlotObject = false;
+ }
+
node = node->next;
if (needToUnlock)
m->unlock();
+
+ if (slotObj) {
+ locker.unlock();
+ slotObj->destroyIfLastRef();
+ locker.relock();
+ }
+
sender->disconnectNotify(QMetaObjectPrivate::signal(sender->metaObject(), signal_index));
}
}
@@ -4273,6 +4287,43 @@ void qDeleteInEventHandler(QObject *o)
*/
/*!
+ \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
Implementation of the template version of connect
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 15b9c8f35e..e2000afc82 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -208,6 +208,7 @@ public:
#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, Functor functor);
+ static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type);
#else
//Connect a signal to a pointer to qobject member function
template <typename Func1, typename Func2>
@@ -245,6 +246,16 @@ public:
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)
{
+ 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<Func2> SlotType;
@@ -259,11 +270,15 @@ public:
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 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,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
- Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
+ type, types, &SignalType::Object::staticMetaObject);
}
//connect to a functor
@@ -271,6 +286,15 @@ public:
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)
{
+ 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)
typedef QtPrivate::FunctionPointer<Func1> SignalType;
const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
@@ -292,9 +316,10 @@ public:
C++11 variadic templates
*/
#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>
- 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 ;
#else
typedef QtPrivate::FunctionPointer<decltype(&Func2::operator())> SlotType ;
@@ -315,11 +340,15 @@ public:
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
"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,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
- Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
+ type, types, &SignalType::Object::staticMetaObject);
}
#endif //Q_QDOC
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index d775ef1b65..fb6601f21b 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -129,7 +129,7 @@ namespace QtPrivate {
its call function is the same as the FunctionPointer::call function.
*/
#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
template<class Obj, typename Ret> struct FunctionPointer<Ret (Obj::*) ()>
{
@@ -137,7 +137,7 @@ namespace QtPrivate {
typedef void Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) ();
- enum {ArgumentCount = 0};
+ enum {ArgumentCount = 0, IsPointerToMemberFunction = true};
template <typename Args, typename R>
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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1);
- enum {ArgumentCount = 1};
+ enum {ArgumentCount = 1, IsPointerToMemberFunction = true};
template <typename Args, typename R>
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]);
@@ -159,7 +159,7 @@ namespace QtPrivate {
typedef List<Arg1, List<Arg2, void> > Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2);
- enum {ArgumentCount = 2};
+ enum {ArgumentCount = 2, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3);
- enum {ArgumentCount = 3};
+ enum {ArgumentCount = 3, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4);
- enum {ArgumentCount = 4};
+ enum {ArgumentCount = 4, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5);
- enum {ArgumentCount = 5};
+ enum {ArgumentCount = 5, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
- enum {ArgumentCount = 6};
+ enum {ArgumentCount = 6, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) () const;
- enum {ArgumentCount = 0};
+ enum {ArgumentCount = 0, IsPointerToMemberFunction = true};
template <typename Args, typename R>
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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1) const;
- enum {ArgumentCount = 1};
+ enum {ArgumentCount = 1, IsPointerToMemberFunction = true};
template <typename Args, typename R>
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]);
@@ -259,7 +259,7 @@ namespace QtPrivate {
typedef List<Arg1, List<Arg2, void> > Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2) const;
- enum {ArgumentCount = 2};
+ enum {ArgumentCount = 2, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3) const;
- enum {ArgumentCount = 3};
+ enum {ArgumentCount = 3, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4) const;
- enum {ArgumentCount = 4};
+ enum {ArgumentCount = 4, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5) const;
- enum {ArgumentCount = 5};
+ enum {ArgumentCount = 5, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret ReturnType;
typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const;
- enum {ArgumentCount = 6};
+ enum {ArgumentCount = 6, IsPointerToMemberFunction = true};
template <typename Args, typename R>
static void call(Function f, Obj *o, void **arg) {
(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 Ret (*Function) ();
typedef Ret ReturnType;
- enum {ArgumentCount = 0};
+ enum {ArgumentCount = 0, IsPointerToMemberFunction = false};
template <typename Args, typename R>
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 Ret ReturnType;
typedef Ret (*Function) (Arg1);
- enum {ArgumentCount = 1};
+ enum {ArgumentCount = 1, IsPointerToMemberFunction = false};
template <typename Args, typename R>
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]); }
@@ -355,7 +355,7 @@ namespace QtPrivate {
typedef List<Arg1, List<Arg2, void> > Arguments;
typedef Ret ReturnType;
typedef Ret (*Function) (Arg1, Arg2);
- enum {ArgumentCount = 2};
+ enum {ArgumentCount = 2, IsPointerToMemberFunction = false};
template <typename Args, typename R>
static void call(Function f, void *, void **arg) {
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 Ret ReturnType;
typedef Ret (*Function) (Arg1, Arg2, Arg3);
- enum {ArgumentCount = 3};
+ enum {ArgumentCount = 3, IsPointerToMemberFunction = false};
template <typename Args, typename R>
static void call(Function f, void *, void **arg) {
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 Ret ReturnType;
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4);
- enum {ArgumentCount = 4};
+ enum {ArgumentCount = 4, IsPointerToMemberFunction = false};
template <typename Args, typename R>
static void call(Function f, void *, void **arg) {
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;
typedef Ret ReturnType;
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5);
- enum {ArgumentCount = 5};
+ enum {ArgumentCount = 5, IsPointerToMemberFunction = false};
template <typename Args, typename R>
static void call(Function f, void *, void **arg) {
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 Ret ReturnType;
typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
- enum {ArgumentCount = 6};
+ enum {ArgumentCount = 6, IsPointerToMemberFunction = false};
template <typename Args, typename R>
static void call(Function f, void *, void **arg) {
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
{ typedef typename IndexesAppend<typename Indexes<N - 1>::Value, N - 1>::Value 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 <int... II, typename... SignalArgs, typename R, typename Function>
@@ -521,7 +521,7 @@ namespace QtPrivate {
typedef List<Args...> Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Args...);
- enum {ArgumentCount = sizeof...(Args)};
+ enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
template <typename SignalArgs, typename R>
static void call(Function f, Obj *o, void **arg) {
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
@@ -533,7 +533,7 @@ namespace QtPrivate {
typedef List<Args...> Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Args...) const;
- enum {ArgumentCount = sizeof...(Args)};
+ enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
template <typename SignalArgs, typename R>
static void call(Function f, Obj *o, void **arg) {
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, o, arg);
@@ -545,7 +545,7 @@ namespace QtPrivate {
typedef List<Args...> Arguments;
typedef Ret ReturnType;
typedef Ret (*Function) (Args...);
- enum {ArgumentCount = sizeof...(Args)};
+ enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = false};
template <typename SignalArgs, typename R>
static void call(Function f, void *, void **arg) {
FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Function>::call(f, arg);
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 081dc8a857..05d81c2bd1 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -90,7 +90,7 @@ private slots:
void thread();
void thread0();
void moveToThread();
- void sender();
+ void senderTest();
void declareInterface();
void qpointerResetBeforeDestroyedSignal();
void testUserData();
@@ -144,7 +144,11 @@ private slots:
void connectPrivateSlots();
void connectFunctorArgDifference();
void connectFunctorOverloads();
+ void connectFunctorQueued();
+ void connectFunctorWithContext();
+ void connectStaticSlotWithObject();
void disconnectDoesNotLeakFunctor();
+ void contextDoesNotLeakFunctor();
void connectBase();
void qmlConnect();
};
@@ -2152,7 +2156,7 @@ signals:
void theSignal();
};
-void tst_QObject::sender()
+void tst_QObject::senderTest()
{
{
SuperObject sender;
@@ -5602,6 +5606,129 @@ void tst_QObject::connectFunctorArgDifference()
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 {
ComplexFunctor(int &overload, QList<QVariant> &result) : overload(overload), result(result) {}
void operator()(int a, int b) {
@@ -5774,6 +5901,23 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
}
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;
{
CountedStruct s;
@@ -5857,6 +6001,67 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
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 {
Q_OBJECT
};