src/corelib/kernel/qobject.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
--- a/src/corelib/kernel/qobject.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/corelib/kernel/qobject.cpp	Wed Mar 31 11:06:36 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -2456,7 +2456,7 @@
     If you pass the Qt::UniqueConnection \a type, the connection will only
     be made if it is not a duplicate. If there is already a duplicate
     (exact same signal to the exact same slot on the same objects),
-    the connection will fail and connect will return false
+    the connection will fail and connect will return false.
 
     The optional \a type parameter describes the type of connection
     to establish. In particular, it determines whether a particular
@@ -2945,7 +2945,6 @@
     return true;
 }
 
-
 /*!\internal
  */
 bool QMetaObject::disconnect(const QObject *sender, int signal_index,
@@ -2956,12 +2955,27 @@
                                           receiver, method_index);
 }
 
+/*!\internal
+
+Disconnect a single signal connection.  If QMetaObject::connect() has been called 
+multiple times for the same sender, signal_index, receiver and method_index only 
+one of these connections will be removed.
+ */
+bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
+                                const QObject *receiver, int method_index)
+{
+    signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index);
+    return QMetaObjectPrivate::disconnect(sender, signal_index,
+                                          receiver, method_index,
+                                          QMetaObjectPrivate::DisconnectOne);
+}
+
 /*! \internal
     Helper function to remove the connection from the senders list and setting the receivers to 0
  */
 bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
                                           const QObject *receiver, int method_index,
-                                          QMutex *senderMutex)
+                                          QMutex *senderMutex, DisconnectType disconnectType)
 {
     bool success = false;
     while (c) {
@@ -2987,6 +3001,9 @@
             c->receiver = 0;
 
             success = true;
+
+            if (disconnectType == DisconnectOne)
+                return success;
         }
         c = c->nextConnectionList;
     }
@@ -2997,7 +3014,8 @@
     Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex
  */
 bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index,
-                                    const QObject *receiver, int method_index)
+                                    const QObject *receiver, int method_index,
+                                    DisconnectType disconnectType)
 {
     if (!sender)
         return false;
@@ -3021,7 +3039,7 @@
         for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) {
             QObjectPrivate::Connection *c =
                 (*connectionLists)[signal_index].first;
-            if (disconnectHelper(c, receiver, method_index, senderMutex)) {
+            if (disconnectHelper(c, receiver, method_index, senderMutex, disconnectType)) {
                 success = true;
                 connectionLists->dirty = true;
             }
@@ -3029,7 +3047,7 @@
     } else if (signal_index < connectionLists->count()) {
         QObjectPrivate::Connection *c =
             (*connectionLists)[signal_index].first;
-        if (disconnectHelper(c, receiver, method_index, senderMutex)) {
+        if (disconnectHelper(c, receiver, method_index, senderMutex, disconnectType)) {
             success = true;
             connectionLists->dirty = true;
         }
@@ -3246,12 +3264,14 @@
 
             const int method = c->method;
             QObjectPrivate::Sender currentSender;
-            currentSender.sender = sender;
-            currentSender.signal = signal_absolute_index;
-            currentSender.ref = 1;
+            const bool receiverInSameThread = currentThreadData == receiver->d_func()->threadData;
             QObjectPrivate::Sender *previousSender = 0;
-            if (currentThreadData == receiver->d_func()->threadData)
+            if (receiverInSameThread) {
+                currentSender.sender = sender;
+                currentSender.signal = signal_absolute_index;
+                currentSender.ref = 1;
                 previousSender = QObjectPrivate::setCurrentSender(receiver, &currentSender);
+            }
             locker.unlock();
 
             if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
@@ -3267,8 +3287,8 @@
                 metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
             } QT_CATCH(...) {
                 locker.relock();
-
-                QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
+                if (receiverInSameThread)
+                    QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
 
                 --connectionLists->inUse;
                 Q_ASSERT(connectionLists->inUse >= 0);
@@ -3283,7 +3303,8 @@
 
             locker.relock();
 
-            QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
+            if (receiverInSameThread)
+                QObjectPrivate::resetCurrentSender(receiver, &currentSender, previousSender);
 
             if (connectionLists->orphaned)
                 break;