summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/kernel/qmetaobject_p.h2
-rw-r--r--src/corelib/kernel/qobject.cpp190
-rw-r--r--src/corelib/kernel/qobject.h14
-rw-r--r--src/corelib/kernel/qobject_p.h11
-rw-r--r--src/corelib/kernel/qobjectdefs.h27
5 files changed, 183 insertions, 61 deletions
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 919273a605..0476558a92 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -137,7 +137,7 @@ struct QMetaObjectPrivate
enum DisconnectType { DisconnectAll, DisconnectOne };
static void memberIndexes(const QObject *obj, const QMetaMethod &member,
int *signalIndex, int *methodIndex);
- static bool connect(const QObject *sender, int signal_index,
+ static QObjectPrivate::Connection *connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index_relative,
const QMetaObject *rmeta = 0,
int type = 0, int *types = 0);
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 6bca22b6df..59282d3464 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -373,7 +373,7 @@ void QObjectPrivate::cleanConnectionLists()
} else {
QObjectPrivate::Connection *next = c->nextConnectionList;
*prev = next;
- delete c;
+ c->deref();
c = next;
}
}
@@ -854,7 +854,7 @@ QObject::~QObject()
while (QObjectPrivate::Connection *c = connectionList.first) {
if (!c->receiver) {
connectionList.first = c->nextConnectionList;
- delete c;
+ c->deref();
continue;
}
@@ -865,11 +865,12 @@ QObject::~QObject()
*c->prev = c->next;
if (c->next) c->next->prev = c->prev;
}
+ c->receiver = 0;
if (needToUnlock)
m->unlock();
connectionList.first = c->nextConnectionList;
- delete c;
+ c->deref();
}
}
@@ -2280,7 +2281,8 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
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 true if the connection succeeds; otherwise returns false.
+ Returns a handle to the connection that can be used to disconnect
+ it later.
You must use the \c SIGNAL() and \c SLOT() macros when specifying
the \a signal and the \a method, for example:
@@ -2309,11 +2311,12 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
in the same order as the order the connection was made, when the
signal is emitted.
- The function returns true if it successfully connects the signal
- to the slot. It will return false if it cannot create the
- connection, for example, if QObject is unable to verify the
- existence of either \a signal or \a method, or if their signatures
- aren't compatible.
+ The function returns a 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 either \a signal or \a method, or if their
+ signatures aren't compatible.
+ You can check if the QMetaObject::Connection is valid by casting it to a bool.
By default, a signal is emitted for every connection you make;
two signals are emitted for duplicate connections. You can break
@@ -2339,15 +2342,15 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
\sa disconnect(), sender(), qRegisterMetaType()
*/
-
-bool QObject::connect(const QObject *sender, const char *signal,
- const QObject *receiver, const char *method,
- Qt::ConnectionType type)
+QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
+ const QObject *receiver, const char *method,
+ Qt::ConnectionType type)
{
{
- const void *cbdata[] = { sender, signal, receiver, method, &type };
+ void *result = 0;
+ const void *cbdata[] = { sender, signal, receiver, method, &type , &result};
if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))
- return true;
+ return QMetaObject::Connection(result);
}
#ifndef QT_NO_DEBUG
@@ -2366,12 +2369,12 @@ bool QObject::connect(const QObject *sender, const char *signal,
(signal && *signal) ? signal+1 : "(null)",
receiver ? receiver->metaObject()->className() : "(null)",
(method && *method) ? method+1 : "(null)");
- return false;
+ return QMetaObject::Connection(0);
}
QByteArray tmp_signal_name;
if (!check_signal_macro(sender, signal, "connect", "bind"))
- return false;
+ return QMetaObject::Connection(0);
const QMetaObject *smeta = sender->metaObject();
const char *signal_arg = signal;
++signal; //skip code
@@ -2393,7 +2396,7 @@ bool QObject::connect(const QObject *sender, const char *signal,
if (signal_index < 0) {
err_method_notfound(sender, signal_arg, "connect");
err_info_about_objects("connect", sender, receiver);
- return false;
+ return QMetaObject::Connection(0);
}
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
int signalOffset, methodOffset;
@@ -2405,7 +2408,7 @@ bool QObject::connect(const QObject *sender, const char *signal,
int membcode = extract_code(method);
if (!check_method_code(membcode, receiver, method, "connect"))
- return false;
+ return QMetaObject::Connection(0);
const char *method_arg = method;
++method; // skip code
@@ -2444,7 +2447,7 @@ bool QObject::connect(const QObject *sender, const char *signal,
if (method_index_relative < 0) {
err_method_notfound(receiver, method_arg, "connect");
err_info_about_objects("connect", sender, receiver);
- return false;
+ return QMetaObject::Connection(0);
}
if (!QMetaObject::checkConnectArgs(signal, method)) {
@@ -2452,13 +2455,13 @@ bool QObject::connect(const QObject *sender, const char *signal,
"\n %s::%s --> %s::%s",
sender->metaObject()->className(), signal,
receiver->metaObject()->className(), method);
- return false;
+ return QMetaObject::Connection(0);
}
int *types = 0;
if ((type == Qt::QueuedConnection)
&& !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))
- return false;
+ return QMetaObject::Connection(0);
#ifndef QT_NO_DEBUG
if (warnCompat) {
@@ -2467,10 +2470,11 @@ bool QObject::connect(const QObject *sender, const char *signal,
check_and_warn_compat(smeta, smethod, rmeta, rmethod);
}
#endif
- if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index_relative, rmeta ,type, types))
- return false;
- const_cast<QObject*>(sender)->connectNotify(signal - 1);
- return true;
+ QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
+ sender, signal_index, receiver, method_index_relative, rmeta ,type, types));
+ if (handle)
+ const_cast<QObject*>(sender)->connectNotify(signal - 1);
+ return handle;
}
/*!
@@ -2478,7 +2482,12 @@ bool QObject::connect(const QObject *sender, const char *signal,
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 true if the connection succeeds; otherwise returns false.
+ Returns a handle to the connection that can be used to disconnect
+ it later.
+
+ The Connection handle will be invalid if it cannot create the
+ connection, for example, the parameters were invalid.
+ You can check if the QMetaObject::Connection is valid by casting it to a bool.
This function works in the same way as
connect(const QObject *sender, const char *signal,
@@ -2490,9 +2499,9 @@ bool QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
Qt::ConnectionType type)
*/
-bool QObject::connect(const QObject *sender, const QMetaMethod &signal,
- const QObject *receiver, const QMetaMethod &method,
- Qt::ConnectionType type)
+QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal,
+ const QObject *receiver, const QMetaMethod &method,
+ Qt::ConnectionType type)
{
#ifndef QT_NO_DEBUG
bool warnCompat = true;
@@ -2513,7 +2522,7 @@ bool QObject::connect(const QObject *sender, const QMetaMethod &signal,
signal.signature(),
receiver ? receiver->metaObject()->className() : "(null)",
method.signature() );
- return false;
+ return QMetaObject::Connection(0);
}
// Reconstructing SIGNAL() macro result for signal.signature() string
@@ -2528,12 +2537,12 @@ bool QObject::connect(const QObject *sender, const QMetaMethod &signal,
methodSignature.append((char)(method.methodType() == QMetaMethod::Slot ? QSLOT_CODE
: method.methodType() == QMetaMethod::Signal ? QSIGNAL_CODE : 0 + '0'));
methodSignature.append(method.signature());
- const void *cbdata[] = { sender, signalSignature.constData(), receiver, methodSignature.constData(), &type };
+ void *result = 0;
+ const void *cbdata[] = { sender, signalSignature.constData(), receiver, methodSignature.constData(), &type, &result };
if (QInternal::activateCallbacks(QInternal::ConnectCallback, (void **) cbdata))
- return true;
+ return QMetaObject::Connection(result);
}
-
int signal_index;
int method_index;
{
@@ -2547,36 +2556,36 @@ bool QObject::connect(const QObject *sender, const QMetaMethod &signal,
if (signal_index == -1) {
qWarning("QObject::connect: Can't find signal %s on instance of class %s",
signal.signature(), smeta->className());
- return false;
+ return QMetaObject::Connection(0);
}
if (method_index == -1) {
qWarning("QObject::connect: Can't find method %s on instance of class %s",
method.signature(), rmeta->className());
- return false;
+ return QMetaObject::Connection(0);
}
-
+
if (!QMetaObject::checkConnectArgs(signal.signature(), method.signature())) {
qWarning("QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s",
smeta->className(), signal.signature(),
rmeta->className(), method.signature());
- return false;
+ return QMetaObject::Connection(0);
}
int *types = 0;
if ((type == Qt::QueuedConnection)
&& !(types = queuedConnectionTypes(signal.parameterTypes())))
- return false;
+ return QMetaObject::Connection(0);
#ifndef QT_NO_DEBUG
if (warnCompat)
check_and_warn_compat(smeta, signal, rmeta, method);
#endif
- if (!QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, 0, type, types))
- return false;
-
- const_cast<QObject*>(sender)->connectNotify(signalSignature.constData());
- return true;
+ QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
+ sender, signal_index, receiver, method_index, 0, type, types));
+ if (handle)
+ const_cast<QObject*>(sender)->connectNotify(signalSignature.constData());
+ return handle;
}
/*!
@@ -2958,22 +2967,24 @@ static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_in
if \a signal_index is -1, then we effectively connect *all* signals
from the sender to the receiver's slot
*/
-bool QMetaObject::connect(const QObject *sender, int signal_index,
- const QObject *receiver, int method_index, int type, int *types)
+QMetaObject::Connection QMetaObject::connect(const QObject *sender, int signal_index,
+ const QObject *receiver, int method_index, int type, int *types)
{
signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index);
- return QMetaObjectPrivate::connect(sender, signal_index,
+ return Connection(QMetaObjectPrivate::connect(sender, signal_index,
receiver, method_index,
0, //FIXME, we could speed this connection up by computing the relative index
- type, types);
+ type, types));
}
/*! \internal
Same as the QMetaObject::connect, but \a signal_index must be the result of QObjectPrivate::signalIndex
method_index is relative to the rmeta metaobject, if rmeta is null, then it is absolute index
+
+ the QObjectPrivate::Connection* has a refcount of 2, so it must be passed to a QMetaObject::Connection
*/
-bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
+QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
const QMetaObject *rmeta, int type, int *types)
{
@@ -2998,7 +3009,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
while (c2) {
if (c2->receiver == receiver && c2->method() == method_index_absolute)
- return false;
+ return 0;
c2 = c2->nextConnectionList;
}
}
@@ -3030,8 +3041,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f));
}
- c.take(); // stop tracking
- return true;
+ return c.take();
}
/*!\internal
@@ -4032,6 +4042,82 @@ void qDeleteInEventHandler(QObject *o)
delete o;
}
+/*!
+ Disconnect a connection.
+
+ If the \a connection is invalid or has already been disconnected, do nothing
+ and return false.
+
+ \sa connect()
+ */
+bool QObject::disconnect(const QMetaObject::Connection &connection)
+{
+ QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(connection.d_ptr);
+
+ if (!c || !c->receiver)
+ return false;
+
+ QMutex *senderMutex = signalSlotLock(c->sender);
+ QMutex *receiverMutex = signalSlotLock(c->receiver);
+ QOrderedMutexLocker locker(senderMutex, receiverMutex);
+
+ QObjectConnectionListVector *connectionLists = QObjectPrivate::get(c->sender)->connectionLists;
+ Q_ASSERT(connectionLists);
+ connectionLists->dirty = true;
+
+ *c->prev = c->next;
+ if (c->next)
+ c->next->prev = c->prev;
+ c->receiver = 0;
+ return true;
+}
+
+/*! \class QMetaObject::Connection
+ Represents a handle to a signal-slot connection.
+ It can be used to disconnect that connection, or check if
+ the connection was successful
+
+ \sa QObject::disconnect
+ */
+
+/*!
+ Create a copy of the handle to the connection
+ */
+QMetaObject::Connection::Connection(const QMetaObject::Connection &other) : d_ptr(other.d_ptr)
+{
+ if (d_ptr)
+ static_cast<QObjectPrivate::Connection *>(d_ptr)->ref();
+}
+
+QMetaObject::Connection& QMetaObject::Connection::operator=(const QMetaObject::Connection& other)
+{
+ if (other.d_ptr != d_ptr) {
+ if (d_ptr)
+ static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
+ d_ptr = other.d_ptr;
+ if (other.d_ptr)
+ static_cast<QObjectPrivate::Connection *>(other.d_ptr)->ref();
+ }
+ return *this;
+}
+
+QMetaObject::Connection::Connection() : d_ptr(0) {}
+
+QMetaObject::Connection::~Connection()
+{
+ if (d_ptr)
+ static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
+}
+
+/*!
+ \fn bool QMetaObject::Connection::operator bool()
+
+ Returns true if the connection is valid.
+
+ The connection is valid if the call to QObject::connect succeeded.
+ The connection is invalid if QObject::connect was not able to find
+ the signal or the slot, or if the arguments do not match.
+ */
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 591c5c88bf..038b59042b 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -194,15 +194,14 @@ public:
void installEventFilter(QObject *);
void removeEventFilter(QObject *);
-
- static bool connect(const QObject *sender, const char *signal,
+ static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
-
- static bool connect(const QObject *sender, const QMetaMethod &signal,
+
+ static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
- inline bool connect(const QObject *sender, const char *signal,
+ inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
static bool disconnect(const QObject *sender, const char *signal,
@@ -214,6 +213,7 @@ public:
{ return disconnect(this, signal, receiver, member); }
inline bool disconnect(const QObject *receiver, const char *member = 0)
{ return disconnect(this, 0, receiver, member); }
+ static bool disconnect(const QMetaObject::Connection &);
void dumpObjectTree();
void dumpObjectInfo();
@@ -275,8 +275,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
};
-inline bool QObject::connect(const QObject *asender, const char *asignal,
- const char *amember, Qt::ConnectionType atype) const
+inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
+ const char *amember, Qt::ConnectionType atype) const
{ return connect(asender, asignal, this, amember, atype); }
#ifndef QT_NO_USERDATA
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index b4c30bd149..2a9334ae8f 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -121,11 +121,22 @@ public:
Connection *next;
Connection **prev;
QAtomicPointer<int> argumentTypes;
+ QAtomicInt ref_;
ushort method_offset;
ushort method_relative;
ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
+ Connection() : nextConnectionList(0), ref_(2) {
+ //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
+ }
~Connection();
int method() const { return method_offset + method_relative; }
+ void ref() { ref_.ref(); }
+ void deref() {
+ if (!ref_.deref()) {
+ Q_ASSERT(!receiver);
+ delete this;
+ }
+ }
};
// ConnectionList is a singly-linked list
struct ConnectionList {
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 31f3067829..1ad24387e0 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -291,6 +291,7 @@ public:
struct Q_CORE_EXPORT QMetaObject
{
+ class Connection;
const char *className() const;
const QMetaObject *superClass() const;
@@ -336,7 +337,7 @@ struct Q_CORE_EXPORT QMetaObject
static QByteArray normalizedType(const char *type);
// internal index-based connect
- static bool connect(const QObject *sender, int signal_index,
+ static Connection connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
int type = 0, int *types = 0);
// internal index-based disconnect
@@ -458,6 +459,30 @@ struct Q_CORE_EXPORT QMetaObject
} d;
};
+class Q_CORE_EXPORT QMetaObject::Connection {
+ void *d_ptr; //QObjectPrivate::Connection*
+ explicit Connection(void *data) : d_ptr(data) { }
+ friend class QObject;
+ friend struct QMetaObject;
+public:
+ ~Connection();
+ Connection();
+ Connection(const Connection &other);
+ Connection &operator=(const Connection &other);
+#ifdef qdoc
+ operator bool() const;
+#else
+ typedef void *Connection::*RestrictedBool;
+ operator RestrictedBool() const { return d_ptr ? &Connection::d_ptr : 0; }
+#endif
+
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline Connection(Connection &&o) : d_ptr(o.d_ptr) { o.d_ptr = 0; }
+ inline Connection &operator=(Connection &&other)
+ { qSwap(d_ptr, other.d_ptr); return *this; }
+#endif
+};
+
typedef const QMetaObject& (*QMetaObjectAccessor)();
struct QMetaObjectExtraData