QObject: add a single shot connection flag
If one needed to listen to a signal just once, one had to store the QMetaObject::Connection object returned by connect() and use it to disconnect the slot after the first signal activation. This has led to a proliferation of using wrappers (and enough TMP); they usually look like this: 1) create a shared_ptr<QMO::Connection>, allocating its payload; 2) create a lambda, capturing the shared_ptr by value; 3) in the lambda, disconnect the connection (through the shared_ptr), and call the actual slot; 4) connect the signal to the lambda, storing the returned QMO::Connection into the shared_ptr. This is expensive, error prone for newcomers, and tricky to support as a general facility inside one's projects. We can do better, just support single shot connections right in QObject. [ChangeLog][QtCore][QObject] Added the Qt::SingleShotConnection flag. When a connection is established with this flag set, the slot is going to be activated at most once; when the signal is emitted, the connection gets automatically broken by Qt. Change-Id: I5f5feeae7f76c9c3d6323d841efba81c8f98ce7e Fixes: QTBUG-44219 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
This commit is contained in:
parent
3e7c63955e
commit
11b8c46d2a
@ -1301,7 +1301,8 @@ namespace Qt {
|
|||||||
DirectConnection,
|
DirectConnection,
|
||||||
QueuedConnection,
|
QueuedConnection,
|
||||||
BlockingQueuedConnection,
|
BlockingQueuedConnection,
|
||||||
UniqueConnection = 0x80
|
UniqueConnection = 0x80,
|
||||||
|
SingleShotConnection = 0x100,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ShortcutContext {
|
enum ShortcutContext {
|
||||||
|
@ -638,6 +638,13 @@
|
|||||||
(i.e. if the same signal is already connected to the same slot
|
(i.e. if the same signal is already connected to the same slot
|
||||||
for the same pair of objects). This flag was introduced in Qt 4.6.
|
for the same pair of objects). This flag was introduced in Qt 4.6.
|
||||||
|
|
||||||
|
\value SingleShotConnection
|
||||||
|
This is a flag that can be combined with any one of the above
|
||||||
|
connection types, using a bitwise OR. When Qt::SingleShotConnection
|
||||||
|
is set, the slot is going to be called only once; the connection
|
||||||
|
will be automatically broken when the signal is emitted.
|
||||||
|
This flag was introduced in Qt 6.0.
|
||||||
|
|
||||||
With queued connections, the parameters must be of types that are
|
With queued connections, the parameters must be of types that are
|
||||||
known to Qt's meta-object system, because Qt needs to copy the
|
known to Qt's meta-object system, because Qt needs to copy the
|
||||||
arguments to store them in an event behind the scenes. If you try
|
arguments to store them in an event behind the scenes. If you try
|
||||||
|
@ -3325,8 +3325,14 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
|
|||||||
c2 = c2->nextConnectionList.loadRelaxed();
|
c2 = c2->nextConnectionList.loadRelaxed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type &= Qt::UniqueConnection - 1;
|
|
||||||
}
|
}
|
||||||
|
type &= ~Qt::UniqueConnection;
|
||||||
|
|
||||||
|
const bool isSingleShot = type & Qt::SingleShotConnection;
|
||||||
|
type &= ~Qt::SingleShotConnection;
|
||||||
|
|
||||||
|
Q_ASSERT(type >= 0);
|
||||||
|
Q_ASSERT(type <= 3);
|
||||||
|
|
||||||
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
|
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
|
||||||
c->sender = s;
|
c->sender = s;
|
||||||
@ -3341,6 +3347,7 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
|
|||||||
c->isSlotObject = false;
|
c->isSlotObject = false;
|
||||||
c->argumentTypes.storeRelaxed(types);
|
c->argumentTypes.storeRelaxed(types);
|
||||||
c->callFunction = callFunction;
|
c->callFunction = callFunction;
|
||||||
|
c->isSingleShot = isSingleShot;
|
||||||
|
|
||||||
QObjectPrivate::get(s)->addConnection(signal_index, c.get());
|
QObjectPrivate::get(s)->addConnection(signal_index, c.get());
|
||||||
|
|
||||||
@ -3632,7 +3639,8 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
|
|||||||
++nargs;
|
++nargs;
|
||||||
|
|
||||||
QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
|
QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
|
||||||
if (!c->receiver.loadRelaxed()) {
|
QObject *receiver = c->receiver.loadRelaxed();
|
||||||
|
if (!receiver) {
|
||||||
// the connection has been disconnected before we got the lock
|
// the connection has been disconnected before we got the lock
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -3658,17 +3666,22 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
|
|||||||
args[n] = types[n].create(argv[n]);
|
args[n] = types[n].create(argv[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->isSingleShot && !QObjectPrivate::disconnect(c)) {
|
||||||
|
delete ev;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
locker.relock();
|
locker.relock();
|
||||||
if (c->isSlotObject)
|
if (c->isSlotObject)
|
||||||
c->slotObj->destroyIfLastRef();
|
c->slotObj->destroyIfLastRef();
|
||||||
if (!c->receiver.loadRelaxed()) {
|
if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
|
||||||
// the connection has been disconnected while we were unlocked
|
// the connection has been disconnected while we were unlocked
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
delete ev;
|
delete ev;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCoreApplication::postEvent(c->receiver.loadRelaxed(), ev);
|
QCoreApplication::postEvent(receiver, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool callbacks_enabled>
|
template <bool callbacks_enabled>
|
||||||
@ -3762,10 +3775,14 @@ void doActivate(QObject *sender, int signal_index, void **argv)
|
|||||||
sender->metaObject()->className(), sender,
|
sender->metaObject()->className(), sender,
|
||||||
receiver->metaObject()->className(), receiver);
|
receiver->metaObject()->className(), receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->isSingleShot && !QObjectPrivate::disconnect(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
QSemaphore semaphore;
|
QSemaphore semaphore;
|
||||||
{
|
{
|
||||||
QBasicMutexLocker locker(signalSlotLock(receiver));
|
QBasicMutexLocker locker(signalSlotLock(receiver));
|
||||||
if (!c->receiver.loadAcquire())
|
if (!c->isSingleShot && !c->receiver.loadAcquire())
|
||||||
continue;
|
continue;
|
||||||
QMetaCallEvent *ev = c->isSlotObject ?
|
QMetaCallEvent *ev = c->isSlotObject ?
|
||||||
new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
|
new QMetaCallEvent(c->slotObj, sender, signal_index, argv, &semaphore) :
|
||||||
@ -3778,6 +3795,9 @@ void doActivate(QObject *sender, int signal_index, void **argv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->isSingleShot && !QObjectPrivate::disconnect(c))
|
||||||
|
continue;
|
||||||
|
|
||||||
QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
|
QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
|
||||||
|
|
||||||
if (c->isSlotObject) {
|
if (c->isSlotObject) {
|
||||||
@ -4855,7 +4875,7 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
|
|||||||
*/
|
*/
|
||||||
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
|
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
|
||||||
const QObject *receiver, void **slot,
|
const QObject *receiver, void **slot,
|
||||||
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
|
QtPrivate::QSlotObjectBase *slotObj, int type,
|
||||||
const int *types, const QMetaObject *senderMetaObject)
|
const int *types, const QMetaObject *senderMetaObject)
|
||||||
{
|
{
|
||||||
if (!sender || !receiver || !slotObj || !senderMetaObject) {
|
if (!sender || !receiver || !slotObj || !senderMetaObject) {
|
||||||
@ -4889,8 +4909,14 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
|
|||||||
c2 = c2->nextConnectionList.loadRelaxed();
|
c2 = c2->nextConnectionList.loadRelaxed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
|
|
||||||
}
|
}
|
||||||
|
type &= ~Qt::UniqueConnection;
|
||||||
|
|
||||||
|
const bool isSingleShot = type & Qt::SingleShotConnection;
|
||||||
|
type &= ~Qt::SingleShotConnection;
|
||||||
|
|
||||||
|
Q_ASSERT(type >= 0);
|
||||||
|
Q_ASSERT(type <= 3);
|
||||||
|
|
||||||
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
|
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
|
||||||
c->sender = s;
|
c->sender = s;
|
||||||
@ -4906,6 +4932,7 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
|
|||||||
c->argumentTypes.storeRelaxed(types);
|
c->argumentTypes.storeRelaxed(types);
|
||||||
c->ownArgumentTypes = false;
|
c->ownArgumentTypes = false;
|
||||||
}
|
}
|
||||||
|
c->isSingleShot = isSingleShot;
|
||||||
|
|
||||||
QObjectPrivate::get(s)->addConnection(signal_index, c.get());
|
QObjectPrivate::get(s)->addConnection(signal_index, c.get());
|
||||||
QMetaObject::Connection ret(c.release());
|
QMetaObject::Connection ret(c.release());
|
||||||
@ -4929,39 +4956,12 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
|
|||||||
bool QObject::disconnect(const QMetaObject::Connection &connection)
|
bool QObject::disconnect(const QMetaObject::Connection &connection)
|
||||||
{
|
{
|
||||||
QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
|
QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
|
||||||
|
const bool disconnected = QObjectPrivate::disconnect(c);
|
||||||
if (!c)
|
if (disconnected) {
|
||||||
return false;
|
const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
|
||||||
QObject *receiver = c->receiver.loadRelaxed();
|
c->deref(); // has been removed from the QMetaObject::Connection object
|
||||||
if (!receiver)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QBasicMutex *senderMutex = signalSlotLock(c->sender);
|
|
||||||
QBasicMutex *receiverMutex = signalSlotLock(receiver);
|
|
||||||
|
|
||||||
QObjectPrivate::ConnectionData *connections;
|
|
||||||
{
|
|
||||||
QOrderedMutexLocker locker(senderMutex, receiverMutex);
|
|
||||||
|
|
||||||
// load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
|
|
||||||
receiver = c->receiver.loadRelaxed();
|
|
||||||
if (!receiver)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
|
|
||||||
Q_ASSERT(connections);
|
|
||||||
connections->removeConnection(c);
|
|
||||||
}
|
}
|
||||||
|
return disconnected;
|
||||||
connections->cleanOrphanedConnections(c->sender);
|
|
||||||
|
|
||||||
c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(),
|
|
||||||
c->signal_index));
|
|
||||||
|
|
||||||
const_cast<QMetaObject::Connection &>(connection).d_ptr = nullptr;
|
|
||||||
c->deref(); // has been removed from the QMetaObject::Connection object
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
|
/*! \fn template<typename PointerToMemberFunction> bool QObject::disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method)
|
||||||
@ -5084,6 +5084,43 @@ bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **
|
|||||||
return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, sender, -1, slot);
|
return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, sender, -1, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
\threadsafe
|
||||||
|
*/
|
||||||
|
bool QObjectPrivate::disconnect(QObjectPrivate::Connection *c)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
return false;
|
||||||
|
QObject *receiver = c->receiver.loadRelaxed();
|
||||||
|
if (!receiver)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QBasicMutex *senderMutex = signalSlotLock(c->sender);
|
||||||
|
QBasicMutex *receiverMutex = signalSlotLock(receiver);
|
||||||
|
|
||||||
|
QObjectPrivate::ConnectionData *connections;
|
||||||
|
{
|
||||||
|
QOrderedMutexLocker locker(senderMutex, receiverMutex);
|
||||||
|
|
||||||
|
// load receiver once again and recheck to ensure nobody else has removed the connection in the meantime
|
||||||
|
receiver = c->receiver.loadRelaxed();
|
||||||
|
if (!receiver)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
connections = QObjectPrivate::get(c->sender)->connections.loadRelaxed();
|
||||||
|
Q_ASSERT(connections);
|
||||||
|
connections->removeConnection(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
connections->cleanOrphanedConnections(c->sender);
|
||||||
|
|
||||||
|
c->sender->disconnectNotify(QMetaObjectPrivate::signal(c->sender->metaObject(),
|
||||||
|
c->signal_index));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*! \class QMetaObject::Connection
|
/*! \class QMetaObject::Connection
|
||||||
\inmodule QtCore
|
\inmodule QtCore
|
||||||
Represents a handle to a signal-slot (or signal-functor) connection.
|
Represents a handle to a signal-slot (or signal-functor) connection.
|
||||||
|
@ -153,9 +153,10 @@ public:
|
|||||||
ushort method_offset;
|
ushort method_offset;
|
||||||
ushort method_relative;
|
ushort method_relative;
|
||||||
signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
|
signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
|
||||||
ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
|
ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
|
||||||
ushort isSlotObject : 1;
|
ushort isSlotObject : 1;
|
||||||
ushort ownArgumentTypes : 1;
|
ushort ownArgumentTypes : 1;
|
||||||
|
ushort isSingleShot : 1;
|
||||||
Connection() : ref_(2), ownArgumentTypes(true) {
|
Connection() : ref_(2), ownArgumentTypes(true) {
|
||||||
//ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
|
//ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
|
||||||
}
|
}
|
||||||
@ -348,10 +349,11 @@ public:
|
|||||||
|
|
||||||
static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
|
static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
|
||||||
const QObject *receiver, void **slot,
|
const QObject *receiver, void **slot,
|
||||||
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
|
QtPrivate::QSlotObjectBase *slotObj, int type,
|
||||||
const int *types, const QMetaObject *senderMetaObject);
|
const int *types, const QMetaObject *senderMetaObject);
|
||||||
static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
|
static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
|
||||||
static bool disconnect(const QObject *sender, int signal_index, void **slot);
|
static bool disconnect(const QObject *sender, int signal_index, void **slot);
|
||||||
|
static bool disconnect(Connection *c);
|
||||||
|
|
||||||
void ensureConnectionData()
|
void ensureConnectionData()
|
||||||
{
|
{
|
||||||
|
@ -49,6 +49,8 @@
|
|||||||
#include <private/qobject_p.h>
|
#include <private/qobject_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
class tst_QObject : public QObject
|
class tst_QObject : public QObject
|
||||||
@ -154,6 +156,7 @@ private slots:
|
|||||||
void nullReceiver();
|
void nullReceiver();
|
||||||
void functorReferencesConnection();
|
void functorReferencesConnection();
|
||||||
void disconnectDisconnects();
|
void disconnectDisconnects();
|
||||||
|
void singleShotConnection();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QObjectCreatedOnShutdown
|
struct QObjectCreatedOnShutdown
|
||||||
@ -7495,6 +7498,594 @@ void tst_QObject::disconnectDisconnects()
|
|||||||
QCOMPARE(count, 3); // + δ
|
QCOMPARE(count, 3); // + δ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReceiverDisconnecting : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SenderObject *sender;
|
||||||
|
int slotCalledCount = 0;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void aSlotByName()
|
||||||
|
{
|
||||||
|
++slotCalledCount;
|
||||||
|
QVERIFY(!disconnect(sender, SIGNAL(signal1()), this, SLOT(aSlotByName())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void aSlotByPtr()
|
||||||
|
{
|
||||||
|
++slotCalledCount;
|
||||||
|
QVERIFY(!disconnect(sender, &SenderObject::signal1, this, &ReceiverDisconnecting::aSlotByPtr));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeleteThisReceiver : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int counter;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void deleteThis()
|
||||||
|
{
|
||||||
|
++counter;
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int DeleteThisReceiver::counter = 0;
|
||||||
|
|
||||||
|
void tst_QObject::singleShotConnection()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// Non single shot behavior: slot called every time the signal is emitted
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot);
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Non single shot behavior: multiple connections cause multiple invocations
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot);
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
QMetaObject::Connection c2 = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot);
|
||||||
|
QVERIFY(c);
|
||||||
|
QVERIFY(c2);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(c);
|
||||||
|
QVERIFY(c2);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 4);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(c);
|
||||||
|
QVERIFY(c2);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Single shot behavior: slot called only once
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Same, without holding a Connection object
|
||||||
|
SenderObject sender;
|
||||||
|
bool ok = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Single shot, disconnect before emitting
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QVERIFY(QObject::disconnect(c));
|
||||||
|
QVERIFY(!c);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Single shot together with another connection
|
||||||
|
SenderObject sender;
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot));
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 4);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Two single shot, from the same signal, to the same slot
|
||||||
|
SenderObject sender;
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Two single shot, from different signals, to the same slot
|
||||||
|
SenderObject sender;
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal2,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal2();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal2();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Same signal, different connections
|
||||||
|
SenderObject sender;
|
||||||
|
ReceiverObject receiver1, receiver2;
|
||||||
|
receiver1.reset();
|
||||||
|
receiver2.reset();
|
||||||
|
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&receiver1, &ReceiverObject::slot1));
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&receiver2, &ReceiverObject::slot1,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
QCOMPARE(receiver1.count_slot1, 0);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver1.count_slot1, 1);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver1.count_slot1, 2);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver1.count_slot1, 3);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 1);
|
||||||
|
|
||||||
|
// Reestablish a single shot
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&receiver2, &ReceiverObject::slot1,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
QCOMPARE(receiver1.count_slot1, 3);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver1.count_slot1, 4);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver1.count_slot1, 5);
|
||||||
|
QCOMPARE(receiver2.count_slot1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Check that the slot is invoked with the connection already disconnected
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c;
|
||||||
|
auto breakSlot = [&]() {
|
||||||
|
QVERIFY(!c);
|
||||||
|
++sender.aPublicSlotCalled;
|
||||||
|
};
|
||||||
|
|
||||||
|
c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, breakSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
QVERIFY(!c);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
QVERIFY(!c);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
QVERIFY(!c);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Same
|
||||||
|
SenderObject sender;
|
||||||
|
ReceiverDisconnecting receiver;
|
||||||
|
receiver.sender = &sender;
|
||||||
|
bool ok = connect(&sender, SIGNAL(signal1()),
|
||||||
|
&receiver, SLOT(aSlotByName()),
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 1);
|
||||||
|
|
||||||
|
// reconnect
|
||||||
|
ok = connect(&sender, SIGNAL(signal1()),
|
||||||
|
&receiver, SLOT(aSlotByName()),
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Same
|
||||||
|
SenderObject sender;
|
||||||
|
ReceiverDisconnecting receiver;
|
||||||
|
receiver.sender = &sender;
|
||||||
|
bool ok = connect(&sender, &SenderObject::signal1,
|
||||||
|
&receiver, &ReceiverDisconnecting::aSlotByPtr,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 1);
|
||||||
|
|
||||||
|
// reconnect
|
||||||
|
ok = connect(&sender, &SenderObject::signal1,
|
||||||
|
&receiver, &ReceiverDisconnecting::aSlotByPtr,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(receiver.slotCalledCount, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Reconnect from inside the slot
|
||||||
|
SenderObject sender;
|
||||||
|
std::function<void()> reconnectingSlot;
|
||||||
|
bool reconnect = false;
|
||||||
|
reconnectingSlot = [&]() {
|
||||||
|
++sender.aPublicSlotCalled;
|
||||||
|
if (reconnect) {
|
||||||
|
QObject::connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, reconnectingSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ok = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, reconnectingSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
reconnect = true;
|
||||||
|
ok = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, reconnectingSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection));
|
||||||
|
QVERIFY(ok);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 2);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 3);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 4);
|
||||||
|
|
||||||
|
reconnect = false;
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 5);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Delete the receiver from inside the slot
|
||||||
|
SenderObject sender;
|
||||||
|
QPointer<DeleteThisReceiver> p = new DeleteThisReceiver;
|
||||||
|
DeleteThisReceiver::counter = 0;
|
||||||
|
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
p.get(), &DeleteThisReceiver::deleteThis,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::SingleShotConnection)));
|
||||||
|
|
||||||
|
QVERIFY(p);
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 1);
|
||||||
|
QVERIFY(!p);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 1);
|
||||||
|
QVERIFY(!p);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Queued, non single shot
|
||||||
|
SenderObject sender;
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection)));
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QTRY_COMPARE(sender.aPublicSlotCalled, 3);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 3);
|
||||||
|
|
||||||
|
QTRY_COMPARE(sender.aPublicSlotCalled, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Queued, single shot
|
||||||
|
SenderObject sender;
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection)));
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QTRY_COMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
QTest::qWait(0);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Queued, single shot, checking the connection handle
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QTRY_COMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
QVERIFY(!c);
|
||||||
|
QTest::qWait(0);
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Queued, single shot, disconnect before emitting
|
||||||
|
SenderObject sender;
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection)));
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QVERIFY(QObject::disconnect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot));
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QTest::qWait(0);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Queued, single shot, disconnect before emitting by using the connection handle
|
||||||
|
SenderObject sender;
|
||||||
|
QMetaObject::Connection c = connect(&sender, &SenderObject::signal1,
|
||||||
|
&sender, &SenderObject::aPublicSlot,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
|
||||||
|
QVERIFY(c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QVERIFY(QObject::disconnect(c));
|
||||||
|
QVERIFY(!c);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
|
||||||
|
QTest::qWait(0);
|
||||||
|
QVERIFY(!c);
|
||||||
|
QCOMPARE(sender.aPublicSlotCalled, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Queued, single shot, delete the receiver from inside the slot
|
||||||
|
SenderObject sender;
|
||||||
|
QPointer<DeleteThisReceiver> p = new DeleteThisReceiver;
|
||||||
|
DeleteThisReceiver::counter = 0;
|
||||||
|
|
||||||
|
QVERIFY(connect(&sender, &SenderObject::signal1,
|
||||||
|
p.get(), &DeleteThisReceiver::deleteThis,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection)));
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(p);
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(p);
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 0);
|
||||||
|
|
||||||
|
sender.emitSignal1();
|
||||||
|
QVERIFY(p);
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 0);
|
||||||
|
|
||||||
|
QTRY_COMPARE(DeleteThisReceiver::counter, 1);
|
||||||
|
QVERIFY(!p);
|
||||||
|
QTest::qWait(0);
|
||||||
|
QCOMPARE(DeleteThisReceiver::counter, 1);
|
||||||
|
QVERIFY(!p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test for QtPrivate::HasQ_OBJECT_Macro
|
// Test for QtPrivate::HasQ_OBJECT_Macro
|
||||||
static_assert(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
|
static_assert(QtPrivate::HasQ_OBJECT_Macro<tst_QObject>::Value);
|
||||||
static_assert(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
|
static_assert(!QtPrivate::HasQ_OBJECT_Macro<SiblingDeleter>::Value);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user