QDBusServiceWatcher: Move the logic to QDBusConnectionPrivate

With kdbus, we won't have a regular signal, but instead a special
message. So keep the logic of what to do in QDBusConnectionPrivate.

The #ifdef is to make sure the bootstrapped qdbuscpp2xml continues to
build in cross-compilation environments.

Change-Id: Iee8cbc07c4434ce9b560ffff13d06f0d9904cb6d
Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
This commit is contained in:
Thiago Macieira 2015-03-30 17:53:06 -07:00
parent 186d881440
commit f744aece9d
5 changed files with 184 additions and 37 deletions

View File

@ -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);

View File

@ -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))

View File

@ -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)));
}
/*!

View File

@ -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

View File

@ -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"