summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel/qobject.cpp
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2011-11-23 15:06:30 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-25 01:12:14 +0100
commit583c55b243d9894d93d32fbe15bece2a9beb1d10 (patch)
treedb6237144cfb511cac1468bf851cf66639a84367 /src/corelib/kernel/qobject.cpp
parent79f675a1e0f628bbc25345ebc1eb1f5809166c6b (diff)
New QObject connection syntax
In addition to the old connection syntax, you can now connect using function pointers. connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue ); You can connect also to functor or C++11 lambdas The connections are now type safe (no more problems with namespaces or typedefs). Implicit type conversion is also supported. The new syntax forces us to change the meaning of signal form protected to public, in order to be able to access the signal's address everywhere The way it works is by introducing new overload of QObject::connect that take function pointer as parametter. Those new overload are template function, that are implemented inline. The actual implementation is in QObject::connectImpl which take a QObject::QSlotObject* as parametter for the slot. That slot object contains a virtual function which call the slot which has to be implemented in the header as it depends on the template parametter. So the internals of QObjectPrivate::Connection will store this QObjectSlot* in order to be able to make the call. You can read a full description here: http://developer.qt.nokia.com/wiki/New_Signal_Slot_Syntax History of commits before it was imported on gerrit: https://qt.gitorious.org/~ogoffart/qt/ogoffarts-qtbase/commits/qobject_connect_ptr Thread on the mailing list: http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000796.html http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-September/001248.html (The discussions on the mailing list were about trying to find a solution that do not need making signals public, but no user friendly solution was found) Note: support for QueuedConnection, and the symetric QObject::disconnect is added in another commit. Qt::UniqueConnection is not supported yet in the new overload. Change-Id: I67d08436b0720e7f2992be9f7e34770960fa58fa Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel/qobject.cpp')
-rw-r--r--src/corelib/kernel/qobject.cpp164
1 files changed, 159 insertions, 5 deletions
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 59282d3464..e8735d0c09 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -923,9 +923,13 @@ QObject::~QObject()
QObjectPrivate::Connection::~Connection()
{
- int *v = argumentTypes.load();
- if (v != &DIRECT_CONNECTION_ONLY)
- delete [] v;
+ if (ownArgumentTypes) {
+ const int *v = argumentTypes.load();
+ if (v != &DIRECT_CONNECTION_ONLY)
+ delete [] v;
+ }
+ if (isSlotObject && !slotObj->ref.deref())
+ delete slotObj;
}
@@ -3022,6 +3026,7 @@ QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, i
c->method_relative = method_index;
c->method_offset = method_offset;
c->connectionType = type;
+ c->isSlotObject = false;
c->argumentTypes.store(types);
c->nextConnectionList = 0;
c->callFunction = callFunction;
@@ -3231,7 +3236,7 @@ void QMetaObject::connectSlotsByName(QObject *o)
static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv)
{
- int *argumentTypes = c->argumentTypes.load();
+ const int *argumentTypes = c->argumentTypes.load();
if (!argumentTypes && argumentTypes != &DIRECT_CONNECTION_ONLY) {
QMetaMethod m = sender->metaObject()->method(signal);
argumentTypes = queuedConnectionTypes(m.parameterTypes());
@@ -3392,7 +3397,12 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
}
const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;
const int method_relative = c->method_relative;
- if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
+ if (c->isSlotObject) {
+ QExplicitlySharedDataPointer<QObject::QSlotObjectBase> obj(c->slotObj);
+ locker.unlock();
+ obj->call(receiver, argv ? argv : empty_argv);
+ locker.relock();
+ } else if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
//we compare the vtable to make sure we are not in the destructor of the object.
locker.unlock();
if (qt_signal_spy_callback_set.slot_begin_callback != 0)
@@ -4043,6 +4053,146 @@ void qDeleteInEventHandler(QObject *o)
}
/*!
+ \fn QMetaObject::Connection QObject::connect(const QObject *sender, (T::*signal)(...), const QObject *receiver, (T::*method)(...), Qt::ConnectionType type)
+
+ \threadsafe
+
+ Creates a connection of the given \a type from the \a signal in
+ the \a sender object to the \a method in the \a receiver object.
+ Returns a handle to the connection that can be used to disconnect
+ it later.
+
+ The signal must be a function declared as a signal in the header.
+ The slot function can be any member function that can be connected
+ to the signal.
+ A slot can be connected to a given signal if the signal has at
+ least as many arguments as the slot, and there is an implicit
+ conversion between the types of the corresponding arguments in the
+ signal and the slot.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 44
+
+ This example ensures that the label always displays the current
+ line edit text.
+
+ A signal can be connected to many slots and signals. Many signals
+ can be connected to one slot.
+
+ If a signal is connected to several slots, the slots are activated
+ in the same order as the order the connection was made, when the
+ signal is emitted
+
+ The function returns an handle to a connection if it successfully
+ connects the signal to the slot. The Connection handle will be invalid
+ if it cannot create the connection, for example, if QObject is unable
+ to verify the existence of \a signal (if it was not declared as a signal)
+ You can check if the QMetaObject::Connection is valid by casting it to a bool.
+
+ The optional \a type parameter describes the type of connection
+ to establish. In particular, it determines whether a particular
+ signal is delivered to a slot immediately or queued for delivery
+ at a later time. If the signal is queued, the parameters must be
+ of types that are 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 to use a queued connection and get the error
+ message
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 25
+
+ make sure to declare the argument type with Q_DECLARE_METATYPE
+
+ A signal is emitted for every connection you make;
+ two signals are emitted for duplicate connections.
+ This overload does not support the type Qt::UniqueConnection
+ */
+
+
+/*!
+ \fn QMetaObject::Connection QObject::connect(const QObject *sender, (T::*signal)(...), Functor functor)
+
+ \threadsafe
+ \overload
+
+ Creates a connection of the given \a type from the \a signal in
+ the \a sender object to the \a functor 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 doc/src/snippets/code/src_corelib_kernel_qobject.cpp 45
+
+ If your compiler support C++11 lambda expressions, you can use them:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 46
+
+ The connection will automatically disconnect if the sender is destroyed.
+ */
+QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal, const QObject *receiver, QObject::QSlotObjectBase *slotObj,
+ Qt::ConnectionType type, const int* types, const QMetaObject* senderMetaObject)
+{
+ int signal_index = -1;
+ void *args[] = { &signal_index, signal };
+ senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
+ if (signal_index < 0 || signal_index >= QMetaObjectPrivate::get(senderMetaObject)->signalCount) {
+ qWarning("QObject::connect: signal not found in %s", senderMetaObject->className());
+ return QMetaObject::Connection(0);
+ }
+ int signalOffset, methodOffset;
+ computeOffsets(senderMetaObject, &signalOffset, &methodOffset);
+ signal_index += signalOffset;
+
+ // duplicated from QMetaObjectPrivate::connect
+ QObject *s = const_cast<QObject *>(sender);
+ QObject *r = const_cast<QObject *>(receiver);
+
+ QOrderedMutexLocker locker(signalSlotLock(sender),
+ signalSlotLock(receiver));
+
+ if (type & Qt::UniqueConnection) {
+ qWarning() << "QObject::connect: Qt::UniqueConnection not supported when connecting function pointers";
+ type = static_cast<Qt::ConnectionType>(type & (Qt::UniqueConnection - 1));
+ }
+
+ QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
+ c->sender = s;
+ c->receiver = r;
+ c->slotObj = slotObj;
+ c->connectionType = type;
+ c->isSlotObject = true;
+ if (types) {
+ c->argumentTypes.store(types);
+ c->ownArgumentTypes = false;
+ }
+
+ QObjectPrivate::get(s)->addConnection(signal_index, c.data());
+
+ c->prev = &(QObjectPrivate::get(r)->senders);
+ c->next = *c->prev;
+ *c->prev = c.data();
+ if (c->next)
+ c->next->prev = &c->next;
+
+ QObjectPrivate *const sender_d = QObjectPrivate::get(s);
+ if (signal_index < 0) {
+ sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0;
+ } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) {
+ sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
+ }
+
+ return QMetaObject::Connection(c.take());
+}
+
+/*!
Disconnect a connection.
If the \a connection is invalid or has already been disconnected, do nothing
@@ -4119,6 +4269,10 @@ QMetaObject::Connection::~Connection()
the signal or the slot, or if the arguments do not match.
*/
+QObject::QSlotObjectBase::~QSlotObjectBase()
+{
+}
+
QT_END_NAMESPACE
#include "moc_qobject.cpp"