summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/dbus/qdbusconnection_p.h7
-rw-r--r--src/dbus/qdbusintegrator.cpp70
-rw-r--r--src/dbus/qdbusservicewatcher.cpp36
-rw-r--r--src/dbus/qdbusservicewatcher.h4
-rw-r--r--tests/auto/dbus/qdbusservicewatcher/tst_qdbusservicewatcher.cpp104
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"