summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/dbus/qdbusabstractinterface.cpp64
-rw-r--r--src/dbus/qdbusabstractinterface_p.h2
-rw-r--r--src/dbus/qdbusintegrator.cpp2
3 files changed, 55 insertions, 13 deletions
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
index 0f097517b7..d63a317612 100644
--- a/src/dbus/qdbusabstractinterface.cpp
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -35,6 +35,7 @@
#include "qdbusabstractinterface.h"
#include "qdbusabstractinterface_p.h"
+#include <qcoreapplication.h>
#include <qthread.h>
#include "qdbusargument.h"
@@ -51,6 +52,29 @@
QT_BEGIN_NAMESPACE
+namespace {
+// ### Qt6: change to a regular QEvent (customEvent)
+// We need to use a QMetaCallEvent here because we can't override customEvent() in
+// Qt 5. Since QDBusAbstractInterface is meant to be derived from, the vtables of
+// classes in generated code will have a pointer to QObject::customEvent instead
+// of to QDBusAbstractInterface::customEvent.
+// See solution in Patch Set 1 of this change in the Qt Gerrit servers.
+// (https://codereview.qt-project.org/#/c/126384/1)
+class DisconnectRelayEvent : public QMetaCallEvent
+{
+public:
+ DisconnectRelayEvent(QObject *sender, const QMetaMethod &m)
+ : QMetaCallEvent(0, 0, Q_NULLPTR, sender, m.methodIndex())
+ {}
+
+ void placeMetaCall(QObject *object) Q_DECL_OVERRIDE
+ {
+ QDBusAbstractInterface *iface = static_cast<QDBusAbstractInterface *>(object);
+ QDBusAbstractInterfacePrivate::finishDisconnectNotify(iface, signalId());
+ }
+};
+}
+
static QDBusError checkIfValid(const QString &service, const QString &path,
const QString &interface, bool isDynamic, bool isPeer)
{
@@ -604,22 +628,38 @@ void QDBusAbstractInterface::disconnectNotify(const QMetaMethod &signal)
if (!d->isValid)
return;
+ // disconnection is just resource freeing, so it can be delayed;
+ // let's do that later, after all the QObject mutexes have been unlocked.
+ QCoreApplication::postEvent(this, new DisconnectRelayEvent(this, signal));
+}
+
+/*!
+ \internal
+ Continues the disconnect notification from above.
+*/
+void QDBusAbstractInterfacePrivate::finishDisconnectNotify(QDBusAbstractInterface *ptr, int signalId)
+{
+ QDBusAbstractInterfacePrivate *d = ptr->d_func();
QDBusConnectionPrivate *conn = d->connectionPrivate();
- if (conn && signal.isValid() && !isSignalConnected(signal))
- return conn->disconnectRelay(d->service, d->path, d->interface,
- this, signal);
if (!conn)
return;
- // wildcard disconnecting, we need to figure out which of our signals are
- // no longer connected to anything
- const QMetaObject *mo = metaObject();
- int midx = QObject::staticMetaObject.methodCount();
- const int end = mo->methodCount();
- for ( ; midx < end; ++midx) {
- QMetaMethod mm = mo->method(midx);
- if (mm.methodType() == QMetaMethod::Signal && !isSignalConnected(mm))
- conn->disconnectRelay(d->service, d->path, d->interface, this, mm);
+ const QMetaObject *mo = ptr->metaObject();
+ QMetaMethod signal = signalId >= 0 ? mo->method(signalId) : QMetaMethod();
+ if (signal.isValid()) {
+ if (!ptr->isSignalConnected(signal))
+ return conn->disconnectRelay(d->service, d->path, d->interface,
+ ptr, signal);
+ } else {
+ // wildcard disconnecting, we need to figure out which of our signals are
+ // no longer connected to anything
+ int midx = QObject::staticMetaObject.methodCount();
+ const int end = mo->methodCount();
+ for ( ; midx < end; ++midx) {
+ QMetaMethod mm = mo->method(midx);
+ if (mm.methodType() == QMetaMethod::Signal && !ptr->isSignalConnected(mm))
+ conn->disconnectRelay(d->service, d->path, d->interface, ptr, mm);
+ }
}
}
diff --git a/src/dbus/qdbusabstractinterface_p.h b/src/dbus/qdbusabstractinterface_p.h
index 1ce457d94b..1d9290b746 100644
--- a/src/dbus/qdbusabstractinterface_p.h
+++ b/src/dbus/qdbusabstractinterface_p.h
@@ -91,6 +91,8 @@ public:
{ return QDBusConnectionPrivate::d(connection); }
void _q_serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+
+ static void finishDisconnectNotify(QDBusAbstractInterface *iface, int signalId);
};
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 7203f05a9b..c465706913 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -2278,7 +2278,7 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service,
sig.append(signal.methodSignature());
if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, sig,
QDBusAbstractInterface::staticMetaObject.methodCount(), true))
- return; // don't connect
+ return; // don't disconnect
Q_ASSERT(thread() != QThread::currentThread());
emit signalNeedsDisconnecting(key, hook);