diff options
-rw-r--r-- | src/dbus/qdbusconnection_p.h | 7 | ||||
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 70 | ||||
-rw-r--r-- | src/dbus/qdbusservicewatcher.cpp | 36 | ||||
-rw-r--r-- | src/dbus/qdbusservicewatcher.h | 4 | ||||
-rw-r--r-- | tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp | 104 |
5 files changed, 184 insertions, 37 deletions
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 1cd7669770..5f7f58e549 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -63,6 +63,7 @@ #include "qdbus_symbols_p.h" #include <qdbusmessage.h> +#include <qdbusservicewatcher.h> // for the WatchMode enum #ifndef QT_NO_DBUS @@ -198,6 +199,12 @@ public: QString getNameOwner(const QString &service); + bool shouldWatchService(const QString &service); + void watchService(const QString &service, QDBusServiceWatcher::WatchMode mode, + QObject *obj, const char *member); + void unwatchService(const QString &service, QDBusServiceWatcher::WatchMode mode, + QObject *obj, const char *member); + bool send(const QDBusMessage &message); QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1); QDBusMessage sendWithReplyLocal(const QDBusMessage &message); diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index cfcf587423..0a95a8e781 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -445,11 +445,27 @@ static QObject *findChildObject(const QDBusConnectionPrivate::ObjectTreeNode *ro return 0; } -static bool shouldWatchService(const QString &service) +static QStringList matchArgsForService(const QString &service, QDBusServiceWatcher::WatchMode mode) { - return !service.isEmpty() && !service.startsWith(QLatin1Char(':')); + QStringList matchArgs; + matchArgs << service; + + switch (mode) { + case QDBusServiceWatcher::WatchForOwnerChange: + break; + + case QDBusServiceWatcher::WatchForRegistration: + matchArgs << QString::fromLatin1("", 0); + break; + + case QDBusServiceWatcher::WatchForUnregistration: + matchArgs << QString() << QString::fromLatin1("", 0); + break; + } + return matchArgs; } + extern Q_DBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook); void qDBusAddSpyHook(QDBusSpyHook hook) { @@ -1473,10 +1489,7 @@ void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage for ( ; it != end && it.key() == key; ++it) { const SignalHook &hook = it.value(); if (!hook.service.isEmpty()) { - const QString owner = - shouldWatchService(hook.service) ? - watchedServices.value(hook.service).owner : - hook.service; + QString owner = watchedServices.value(hook.service, WatchedServiceData(hook.service)).owner; if (owner != msg.service()) continue; } @@ -2278,6 +2291,51 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service, } } +bool QDBusConnectionPrivate::shouldWatchService(const QString &service) +{ + // we don't have to watch anything in peer mode + if (mode != ClientMode) + return false; + // we don't have to watch wildcard services (empty strings) + if (service.isEmpty()) + return false; + // we don't have to watch the bus driver + if (service == QDBusUtil::dbusService()) + return false; + return true; +} + +/*! + Sets up a watch rule for service \a service for the change described by + mode \a mode. When the change happens, slot \a member in object \a obj will + be called. + + The caller should call QDBusConnectionPrivate::shouldWatchService() before + calling this function to check whether the service needs to be watched at + all. Failing to do so may add rules that are never activated. +*/ +void QDBusConnectionPrivate::watchService(const QString &service, QDBusServiceWatcher::WatchMode mode, QObject *obj, const char *member) +{ + QStringList matchArgs = matchArgsForService(service, mode); + connectSignal(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(), + matchArgs, QString(), obj, member); +} + +/*! + Removes a watch rule set up by QDBusConnectionPrivate::watchService(). The + arguments to this function must be the same as the ones for that function. + + Sets up a watch rule for service \a service for the change described by + mode \a mode. When the change happens, slot \a member in object \a obj will + be called. +*/ +void QDBusConnectionPrivate::unwatchService(const QString &service, QDBusServiceWatcher::WatchMode mode, QObject *obj, const char *member) +{ + QStringList matchArgs = matchArgsForService(service, mode); + disconnectSignal(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(), + matchArgs, QString(), obj, member); +} + QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName) { if (QDBusUtil::isValidUniqueConnectionName(serviceName)) diff --git a/src/dbus/qdbusservicewatcher.cpp b/src/dbus/qdbusservicewatcher.cpp index 4adf049d17..72c1a12f2c 100644 --- a/src/dbus/qdbusservicewatcher.cpp +++ b/src/dbus/qdbusservicewatcher.cpp @@ -38,6 +38,7 @@ #include <QStringList> #include <private/qobject_p.h> +#include <private/qdbusconnection_p.h> #ifndef QT_NO_DBUS @@ -59,7 +60,6 @@ public: void _q_serviceOwnerChanged(const QString &, const QString &, const QString &); void setConnection(const QStringList &services, const QDBusConnection &c, QDBusServiceWatcher::WatchMode watchMode); - QStringList matchArgsForService(const QString &service); void addService(const QString &service); void removeService(const QString &service); }; @@ -93,40 +93,18 @@ void QDBusServiceWatcherPrivate::setConnection(const QStringList &s, const QDBus } } -QStringList QDBusServiceWatcherPrivate::matchArgsForService(const QString &service) -{ - QStringList matchArgs; - matchArgs << service; - - switch (watchMode) { - case QDBusServiceWatcher::WatchForOwnerChange: - break; - - case QDBusServiceWatcher::WatchForRegistration: - matchArgs << QString::fromLatin1("", 0); - break; - - case QDBusServiceWatcher::WatchForUnregistration: - matchArgs << QString() << QString::fromLatin1("", 0); - break; - } - return matchArgs; -} - void QDBusServiceWatcherPrivate::addService(const QString &service) { - QStringList matchArgs = matchArgsForService(service); - connection.connect(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(), - matchArgs, QString(), q_func(), - SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection); + if (d && d->shouldWatchService(service)) + d->watchService(service, watchMode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString))); } void QDBusServiceWatcherPrivate::removeService(const QString &service) { - QStringList matchArgs = matchArgsForService(service); - connection.disconnect(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(), - matchArgs, QString(), q_func(), - SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection); + if (d && d->shouldWatchService(service)) + d->unwatchService(service, watchMode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString))); } /*! diff --git a/src/dbus/qdbusservicewatcher.h b/src/dbus/qdbusservicewatcher.h index 6f6ce917af..71c0f0af68 100644 --- a/src/dbus/qdbusservicewatcher.h +++ b/src/dbus/qdbusservicewatcher.h @@ -37,7 +37,7 @@ #include <QtCore/qobject.h> #include <QtDBus/qdbusmacros.h> -#ifndef QT_NO_DBUS +#if !defined(QT_NO_DBUS) && !defined(QT_NO_QOBJECT) QT_BEGIN_NAMESPACE @@ -89,5 +89,5 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusServiceWatcher::WatchMode) QT_END_NAMESPACE -#endif // QT_NO_DBUS +#endif // QT_NO_DBUS || QT_NO_QOBJECT #endif // QDBUSSERVICEWATCHER_H diff --git a/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp b/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp index 9dd2e4bb83..e7fa1e6484 100644 --- a/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp +++ b/tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp @@ -49,8 +49,11 @@ private slots: void watchForCreation(); void watchForDisappearance(); + void watchForDisappearanceUniqueConnection(); void watchForOwnerChange(); void modeChange(); + void disconnectedConnection(); + void setConnection(); }; tst_QDBusServiceWatcher::tst_QDBusServiceWatcher() @@ -155,6 +158,40 @@ void tst_QDBusServiceWatcher::watchForDisappearance() QVERIFY(spyO.at(0).at(2).toString().isEmpty()); } +void tst_QDBusServiceWatcher::watchForDisappearanceUniqueConnection() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + QVERIFY(con.isConnected()); + + // second connection + QString watchedName = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "session2").baseService(); + QVERIFY(!watchedName.isEmpty()); + + QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForUnregistration); + watcher.setObjectName("watcher for disappearance"); + + QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString))); + QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString))); + QSignalSpy spyO(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString))); + QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop())); + + // unregister it: + QDBusConnection::disconnectFromBus("session2"); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(spyR.count(), 0); + + QCOMPARE(spyU.count(), 1); + QCOMPARE(spyU.at(0).at(0).toString(), watchedName); + + QCOMPARE(spyO.count(), 1); + QCOMPARE(spyO.at(0).at(0).toString(), watchedName); + QCOMPARE(spyO.at(0).at(1).toString(), watchedName); + QVERIFY(spyO.at(0).at(2).toString().isEmpty()); +} + void tst_QDBusServiceWatcher::watchForOwnerChange() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -263,5 +300,72 @@ void tst_QDBusServiceWatcher::modeChange() QVERIFY(spyO.at(0).at(2).toString().isEmpty()); } +void tst_QDBusServiceWatcher::disconnectedConnection() +{ + QDBusConnection con(""); + QVERIFY(!con.isConnected()); + + QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration); + watcher.addWatchedService("com.example.somethingelse"); + watcher.addWatchedService("org.freedesktop.DBus"); + + watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration); + watcher.setWatchMode(QDBusServiceWatcher::WatchForOwnerChange); + + watcher.setWatchedServices(QStringList()); +} + +void tst_QDBusServiceWatcher::setConnection() +{ + // begin with a disconnected connection + QDBusConnection con(""); + QVERIFY(!con.isConnected()); + + QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration); + + QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString))); + QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString))); + QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceOwnerChanged(QString,QString,QString)), SLOT(exitLoop())); + + // move to the session bus + con = QDBusConnection::sessionBus(); + QVERIFY(con.isConnected()); + watcher.setConnection(con); + + // register a name + QVERIFY(con.registerService(serviceName)); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(spyR.count(), 1); + QCOMPARE(spyR.at(0).at(0).toString(), serviceName); + QCOMPARE(spyU.count(), 0); + + // is the system bus available? + if (!QDBusConnection::systemBus().isConnected()) + return; + + // connect to the system bus and ask to watch that base service + QString watchedName = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system2").baseService(); + watcher.setWatchedServices(QStringList() << watchedName); + watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration); + + // move to the system bus + watcher.setConnection(QDBusConnection::systemBus()); + spyR.clear(); + spyU.clear(); + + QDBusConnection::disconnectFromBus("system2"); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(spyR.count(), 0); + + QCOMPARE(spyU.count(), 1); + QCOMPARE(spyU.at(0).at(0).toString(), watchedName); +} + QTEST_MAIN(tst_QDBusServiceWatcher) #include "tst_qdbusservicewatcher.moc" |