Add support for QueuedConnection when connecting using the new syntax

QMetaCallEvent now can handle a pointer to QSlotObjectBase

Change-Id: I94da1e68ce9bb1fd96a9ae013a389552eb625faa
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Olivier Goffart 2011-11-23 15:03:04 +01:00 committed by Qt by Nokia
parent 583c55b243
commit 66b659c8a4
5 changed files with 98 additions and 13 deletions

View File

@ -498,11 +498,23 @@ void QObjectPrivate::clearGuards(QObject *object)
QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction,
const QObject *sender, int signalId,
int nargs, int *types, void **args, QSemaphore *semaphore)
: QEvent(MetaCall), sender_(sender), signalId_(signalId),
: QEvent(MetaCall), slotObj_(0), sender_(sender), signalId_(signalId),
nargs_(nargs), types_(types), args_(args), semaphore_(semaphore),
callFunction_(callFunction), method_offset_(method_offset), method_relative_(method_relative)
{ }
/*! \internal
*/
QMetaCallEvent::QMetaCallEvent(QObject::QSlotObjectBase *slotO, const QObject *sender, int signalId,
int nargs, int *types, void **args, QSemaphore *semaphore)
: QEvent(MetaCall), slotObj_(slotO), sender_(sender), signalId_(signalId),
nargs_(nargs), types_(types), args_(args), semaphore_(semaphore),
callFunction_(0), method_offset_(0), method_relative_(-1)
{
if (slotObj_)
slotObj_->ref.ref();
}
/*! \internal
*/
QMetaCallEvent::~QMetaCallEvent()
@ -519,13 +531,17 @@ QMetaCallEvent::~QMetaCallEvent()
if (semaphore_)
semaphore_->release();
#endif
if (slotObj_ && !slotObj_->ref.deref())
delete slotObj_;
}
/*! \internal
*/
void QMetaCallEvent::placeMetaCall(QObject *object)
{
if (callFunction_) {
if (slotObj_) {
slotObj_->call(object, args_);
} else if (callFunction_) {
callFunction_(object, QMetaObject::InvokeMetaMethod, method_relative_, args_);
} else {
QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method_offset_ + method_relative_, args_);
@ -3261,11 +3277,10 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
args[0] = 0; // return value
for (int n = 1; n < nargs; ++n)
args[n] = QMetaType::create((types[n] = argumentTypes[n-1]), argv[n]);
QCoreApplication::postEvent(c->receiver, new QMetaCallEvent(c->method_offset,
c->method_relative,
c->callFunction,
sender, signal, nargs,
types, args));
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal, nargs, types, args) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs, types, args);
QCoreApplication::postEvent(c->receiver, ev);
}
@ -3378,12 +3393,10 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
receiver->metaObject()->className(), receiver);
}
QSemaphore semaphore;
QCoreApplication::postEvent(receiver, new QMetaCallEvent(c->method_offset, c->method_relative,
c->callFunction,
sender, signal_absolute_index,
0, 0,
argv ? argv : empty_argv,
&semaphore));
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal_absolute_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_absolute_index, 0, 0, argv ? argv : empty_argv, &semaphore);
QCoreApplication::postEvent(receiver, ev);
semaphore.acquire();
locker.relock();
continue;

View File

@ -221,6 +221,9 @@ public:
typedef typename QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::IncompatibleSignalSlotArguments EnsureCompatibleArguments;
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),
receiver, new QSlotObject<Func2,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
@ -318,6 +321,7 @@ protected:
static const QMetaObject staticQtMetaObject;
friend struct QMetaObject;
friend class QMetaCallEvent;
friend class QApplication;
friend class QApplicationPrivate;
friend class QCoreApplication;

View File

@ -344,6 +344,43 @@ namespace QtPrivate {
#endif
/*
Logic to statically generate the array of qMetaTypeId
ConnectionTypes<FunctionPointer<Signal>::Arguments>::types() returns an array
of int that is suitable for the types arguments of the connection functions.
The array only exist of all the types are declared as a metatype
(detected using the TypesAreDeclaredMetaType helper struct)
If one of the type is not declared, the function return 0 and the signal
cannot be used in queued connection.
*/
#ifndef Q_COMPILER_VARIADIC_TEMPLATES
template <typename ArgList> struct TypesAreDeclaredMetaType { enum { Value = false }; };
template <> struct TypesAreDeclaredMetaType<void> { enum { Value = true }; };
template <typename Arg, typename Tail> struct TypesAreDeclaredMetaType<List<Arg, Tail> > { enum { Value = QMetaTypeId2<Arg>::Defined && TypesAreDeclaredMetaType<Tail>::Value }; };
template <typename ArgList, bool Declared = TypesAreDeclaredMetaType<ArgList>::Value > struct ConnectionTypes
{ static const int *types() { return 0; } };
template <> struct ConnectionTypes<void, true>
{ static const int *types() { static const int t[1] = { 0 }; return t; } };
template <typename Arg1> struct ConnectionTypes<List<Arg1, void>, true>
{ static const int *types() { static const int t[2] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), 0 }; return t; } };
template <typename Arg1, typename Arg2> struct ConnectionTypes<List<Arg1, List<Arg2, void> >, true>
{ static const int *types() { static const int t[3] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(), 0 }; return t; } };
template <typename Arg1, typename Arg2, typename Arg3> struct ConnectionTypes<List<Arg1, List<Arg2, List<Arg3, void> > >, true>
{ static const int *types() { static const int t[4] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(),
QtPrivate::QMetaTypeIdHelper<Arg3>::qt_metatype_id(), 0 }; return t; } };
#else
template <typename ArgList> struct TypesAreDeclaredMetaType { enum { Value = false }; };
template <> struct TypesAreDeclaredMetaType<List<>> { enum { Value = true }; };
template <typename Arg, typename... Tail> struct TypesAreDeclaredMetaType<List<Arg, Tail...> >
{ enum { Value = QMetaTypeId2<Arg>::Defined && TypesAreDeclaredMetaType<List<Tail...>>::Value }; };
template <typename ArgList, bool Declared = TypesAreDeclaredMetaType<ArgList>::Value > struct ConnectionTypes
{ static const int *types() { return 0; } };
template <typename... Args> struct ConnectionTypes<List<Args...>, true>
{ static const int *types() { static const int t[sizeof...(Args) + 1] = { (QtPrivate::QMetaTypeIdHelper<Args>::qt_metatype_id())..., 0 }; return t; } };
#endif
}

View File

@ -264,6 +264,9 @@ class Q_CORE_EXPORT QMetaCallEvent : public QEvent
public:
QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId,
int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0);
QMetaCallEvent(QObject::QSlotObjectBase *slotObj, const QObject *sender, int signalId,
int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0);
~QMetaCallEvent();
inline int id() const { return method_offset_ + method_relative_; }
@ -274,6 +277,7 @@ public:
virtual void placeMetaCall(QObject *object);
private:
QObject::QSlotObjectBase *slotObj_;
const QObject *sender_;
int signalId_;
int nargs_;

View File

@ -2812,6 +2812,10 @@ void tst_QObject::blockingQueuedConnection()
QVERIFY(QMetaObject::invokeMethod(&receiver, "slot1", Qt::BlockingQueuedConnection));
QVERIFY(receiver.called(1));
connect(&sender, &SenderObject::signal2, &receiver, &ReceiverObject::slot2, Qt::BlockingQueuedConnection);
sender.emitSignal2();
QVERIFY(receiver.called(2));
thread.quit();
QVERIFY(thread.wait());
}
@ -4173,6 +4177,29 @@ void tst_QObject::customTypesPointer()
QCOMPARE(checker.received.value(), 0);
checker.doEmit(t1);
QCOMPARE(checker.received.value(), t1.value());
checker.received = t0;
checker.disconnect();
int idx = qRegisterMetaType<CustomType>("CustomType");
QCOMPARE(QMetaType::type("CustomType"), idx);
connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1,
Qt::QueuedConnection);
QCOMPARE(instanceCount, 4);
checker.doEmit(t2);
QCOMPARE(instanceCount, 5);
QCOMPARE(checker.received.value(), t0.value());
QCoreApplication::processEvents();
QCOMPARE(checker.received.value(), t2.value());
QCOMPARE(instanceCount, 4);
QVERIFY(QMetaType::isRegistered(idx));
QCOMPARE(qRegisterMetaType<CustomType>("CustomType"), idx);
QCOMPARE(QMetaType::type("CustomType"), idx);
QVERIFY(QMetaType::isRegistered(idx));
}
QCOMPARE(instanceCount, 3);
}