diff options
-rw-r--r-- | src/dbus/qdbusabstractinterface.cpp | 64 | ||||
-rw-r--r-- | src/dbus/qdbusabstractinterface_p.h | 2 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 2 |
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); |