Index: trunk/src/dbus/qdbusintegrator.cpp
===================================================================
--- trunk/src/dbus/qdbusintegrator.cpp	(revision 651)
+++ trunk/src/dbus/qdbusintegrator.cpp	(revision 769)
@@ -524,5 +524,5 @@
 
     QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message);
-    qDBusDebug() << d << "got message:" << amsg;
+    qDBusDebug() << d << "got message (signal):" << amsg;
 
     return d->handleMessage(amsg) ?
@@ -1661,7 +1661,4 @@
 
     QString busService = QLatin1String(DBUS_SERVICE_DBUS);
-    WatchedServicesHash::mapped_type &bus = watchedServices[busService];
-    bus.refcount = 1;
-    bus.owner = getNameOwnerNoCache(busService);
     connectSignal(busService, QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(),
                   this, SLOT(registerService(QString)));
@@ -1691,7 +1688,21 @@
 {
     Q_ASSERT(pcall->pending);
-    QDBusDispatchLocker locker(PendingCallBlockAction, this);
-    q_dbus_pending_call_block(pcall->pending);
-    // QDBusConnectionPrivate::processFinishedCall() is called automatically
+    Q_ASSERT(!pcall->autoDelete);
+    //Q_ASSERT(pcall->mutex.isLocked()); // there's no such function
+
+    if (pcall->waitingForFinished) {
+        // another thread is already waiting
+        pcall->waitForFinishedCondition.wait(&pcall->mutex);
+    } else {
+        pcall->waitingForFinished = true;
+        pcall->mutex.unlock();
+
+        {
+            QDBusDispatchLocker locker(PendingCallBlockAction, this);
+            q_dbus_pending_call_block(pcall->pending);
+            // QDBusConnectionPrivate::processFinishedCall() is called automatically
+        }
+        pcall->mutex.lock();
+    }
 }
 
@@ -1699,4 +1710,6 @@
 {
     QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
+
+    QMutexLocker locker(&call->mutex);
 
     QDBusMessage &msg = call->replyMessage;
@@ -1729,4 +1742,10 @@
     }
 
+    if (call->pending)
+        q_dbus_pending_call_unref(call->pending);
+    call->pending = 0;
+
+    locker.unlock();
+
     // Are there any watchers?
     if (call->watcherHelper)
@@ -1736,10 +1755,8 @@
         emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage);
 
-    if (call->pending)
-        q_dbus_pending_call_unref(call->pending);
-    call->pending = 0;
-
-    if (call->autoDelete)
+    if (call->autoDelete) {
+        Q_ASSERT(!call->waitingForFinished); // can't wait on a call with autoDelete!
         delete call;
+    }
 }
 
@@ -1883,8 +1900,6 @@
     if (isServiceRegisteredByThread(message.service())) {
         // special case for local calls
-        QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
-        pcall->sentMessage = message;
+        QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
         pcall->replyMessage = sendWithReplyLocal(message);
-        pcall->connection = this;
 
         return pcall;
@@ -1892,6 +1907,5 @@
 
     checkThread();
-    QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate;
-    pcall->sentMessage = message;
+    QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
     pcall->ref = 0;
 
@@ -1917,5 +1931,4 @@
 
             pcall->pending = pending;
-            pcall->connection = this;
             q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
 
@@ -1941,5 +1954,5 @@
     Q_ASSERT(pcall);
 
-    // has it already finished (dispatched locally)?
+    // has it already finished with success (dispatched locally)?
     if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
         pcall->setReplyCallback(receiver, returnMethod);
@@ -1949,11 +1962,14 @@
     }
 
+    // either it hasn't finished or it has finished with error
+    if (errorMethod) {
+        pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+        connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
+                Qt::QueuedConnection);
+        pcall->watcherHelper->moveToThread(thread());
+    }
+
     // has it already finished and is an error reply message?
     if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) {
-        if (errorMethod) {
-            pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
-            connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod);
-            pcall->watcherHelper->moveToThread(thread());
-        }
         processFinishedCall(pcall);
         delete pcall;
@@ -1961,19 +1977,7 @@
     }
 
-    // has it already finished with error?
-    if (pcall->replyMessage.type() != QDBusMessage::InvalidMessage) {
-        delete pcall;
-        return 0;
-    }
-
     pcall->autoDelete = true;
     pcall->ref.ref();
-
     pcall->setReplyCallback(receiver, returnMethod);
-    if (errorMethod) {
-        pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
-        connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod);
-        pcall->watcherHelper->moveToThread(thread());
-    }
 
     return 1;
@@ -2005,5 +2009,6 @@
             entry.signature == hook.signature &&
             entry.obj == hook.obj &&
-            entry.midx == hook.midx) {
+            entry.midx == hook.midx &&
+            entry.argumentMatch == hook.argumentMatch) {
             // no need to compare the parameters if it's the same slot
             return true;        // already there
@@ -2047,8 +2052,5 @@
             if (shouldWatchService(hook.service)) {
                 WatchedServicesHash::mapped_type &data = watchedServices[hook.service];
-                if (data.refcount) {
-                    // already watching
-                    ++data.refcount;
-                } else {
+                if (++data.refcount == 1) {
                     // we need to watch for this service changing
                     QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
@@ -2090,5 +2092,6 @@
             entry.signature == hook.signature &&
             entry.obj == hook.obj &&
-            entry.midx == hook.midx) {
+            entry.midx == hook.midx &&
+            entry.argumentMatch == hook.argumentMatch) {
             // no need to compare the parameters if it's the same slot
             disconnectSignal(it);
@@ -2105,17 +2108,4 @@
 {
     const SignalHook &hook = it.value();
-
-    WatchedServicesHash::Iterator sit = watchedServices.find(hook.service);
-    if (sit != watchedServices.end()) {
-        if (sit.value().refcount == 1) {
-            watchedServices.erase(sit);
-            QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
-            disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
-                          QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
-                          this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
-        } else {
-            --sit.value().refcount;
-        }
-    }
 
     bool erase = false;
@@ -2137,4 +2127,18 @@
         qDBusDebug("Removing rule: %s", hook.matchRule.constData());
         q_dbus_bus_remove_match(connection, hook.matchRule, NULL);
+
+        // Successfully disconnected the signal
+        // Were we watching for this name?
+        WatchedServicesHash::Iterator sit = watchedServices.find(hook.service);
+        if (sit != watchedServices.end()) {
+            if (--sit.value().refcount == 0) {
+                watchedServices.erase(sit);
+                QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
+                disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
+                              QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+                              this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+            }
+        }
+
     }
 
