--- a/src/dbus/qdbusintegrator.cpp Tue Jan 26 12:42:25 2010 +0200
+++ b/src/dbus/qdbusintegrator.cpp Tue Feb 02 00:43:10 2010 +0200
@@ -392,7 +392,7 @@
static QByteArray buildMatchRule(const QString &service, const QString & /*owner*/,
const QString &objectPath, const QString &interface,
- const QString &member, const QString & /*signature*/)
+ const QString &member, const QStringList &argMatch, const QString & /*signature*/)
{
QString result = QLatin1String("type='signal',");
QString keyValue = QLatin1String("%1='%2',");
@@ -406,6 +406,14 @@
if (!member.isEmpty())
result += keyValue.arg(QLatin1String("member"), member);
+ // add the argument string-matching now
+ if (!argMatch.isEmpty()) {
+ keyValue = QLatin1String("arg%1='%2',");
+ for (int i = 0; i < argMatch.count(); ++i)
+ if (!argMatch.at(i).isNull())
+ result += keyValue.arg(i).arg(argMatch.at(i));
+ }
+
result.chop(1); // remove ending comma
return result.toLatin1();
}
@@ -493,6 +501,11 @@
return 0;
}
+static bool shouldWatchService(const QString &service)
+{
+ return !service.isEmpty() && !service.startsWith(QLatin1Char(':'));
+}
+
extern QDBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);
void qDBusAddSpyHook(QDBusSpyHook hook)
{
@@ -921,7 +934,8 @@
rootNode(QString(QLatin1Char('/')))
{
static const bool threads = q_dbus_threads_init_default();
- static const int debugging = ::isDebugging = qgetenv("QDBUS_DEBUG").toInt();
+ static const int debugging = qgetenv("QDBUS_DEBUG").toInt();
+ ::isDebugging = debugging;
Q_UNUSED(threads)
Q_UNUSED(debugging)
@@ -933,9 +947,7 @@
QDBusMetaTypeId::init();
rootNode.flags = 0;
-
- connect(this, SIGNAL(serviceOwnerChanged(QString,QString,QString)),
- this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ watchedServiceNames[QLatin1String(DBUS_SERVICE_DBUS)] = 1;
}
QDBusConnectionPrivate::~QDBusConnectionPrivate()
@@ -1165,11 +1177,7 @@
void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name,
const QString &oldOwner, const QString &newOwner)
{
- if (oldOwner == baseService)
- unregisterService(name);
- if (newOwner == baseService)
- registerService(name);
-
+ Q_UNUSED(oldOwner);
QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
QMutableHashIterator<QString, SignalHook> it(signalHooks);
it.toFront();
@@ -1195,6 +1203,7 @@
bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
const QString &service, const QString &owner,
const QString &path, const QString &interface, const QString &name,
+ const QStringList &argMatch,
QObject *receiver, const char *signal, int minMIdx,
bool buildSignature)
{
@@ -1214,6 +1223,7 @@
hook.owner = owner; // we don't care if the service has an owner yet
hook.path = path;
hook.obj = receiver;
+ hook.argumentMatch = argMatch;
// build the D-Bus signal name and signature
// This should not happen for QDBusConnection::connect, use buildSignature here, since
@@ -1235,7 +1245,7 @@
hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
}
- hook.matchRule = buildMatchRule(service, owner, path, interface, mname, hook.signature);
+ hook.matchRule = buildMatchRule(service, owner, path, interface, mname, argMatch, hook.signature);
return true; // connect to this signal
}
@@ -1478,7 +1488,7 @@
//qDBusDebug() << signalHooks.keys();
for ( ; it != end && it.key() == key; ++it) {
const SignalHook &hook = it.value();
- if (!hook.owner.isEmpty() && hook.owner != msg.service())
+ if (!hook.owner.isNull() && hook.owner != msg.service())
continue;
if (!hook.path.isEmpty() && hook.path != msg.path())
continue;
@@ -1486,6 +1496,24 @@
continue;
if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
continue;
+ if (!hook.argumentMatch.isEmpty()) {
+ const QVariantList arguments = msg.arguments();
+ if (hook.argumentMatch.size() > arguments.size())
+ continue;
+
+ bool matched = true;
+ for (int i = 0; i < hook.argumentMatch.size(); ++i) {
+ const QString ¶m = hook.argumentMatch.at(i);
+ if (param.isNull())
+ continue; // don't try to match against this
+ if (param == arguments.at(i).toString())
+ continue; // matched
+ matched = false;
+ break;
+ }
+ if (!matched)
+ continue;
+ }
activateSignal(hook, msg);
}
@@ -1620,9 +1648,16 @@
baseService = QString::fromUtf8(service);
} else {
- qWarning("QDBusConnectionPrivate::SetConnection: Unable to get base service");
+ qWarning("QDBusConnectionPrivate::setConnection: Unable to get base service");
}
+ QString busService = QLatin1String(DBUS_SERVICE_DBUS);
+ connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(),
+ this, SLOT(registerService(QString)));
+ connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(),
+ this, SLOT(unregisterService(QString)));
+
+
q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
//qDebug("base service: %s", service);
@@ -1933,11 +1968,47 @@
return 1;
}
+bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &owner,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ QString name2 = name;
+ if (name2.isNull())
+ name2.detach();
+
+ hook.signature = signature;
+ if (!prepareHook(hook, key, service, owner, path, interface, name, argumentMatch, receiver, slot, 0, false))
+ return false; // don't connect
+
+ // avoid duplicating:
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key);
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
+ for ( ; it != end && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.owner == hook.owner &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // no need to compare the parameters if it's the same slot
+ return true; // already there
+ }
+ }
+
+ connectSignal(key, hook);
+ return true;
+}
+
void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook)
{
signalHooks.insertMulti(key, hook);
connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
- Qt::DirectConnection);
+ Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection));
MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule);
@@ -1960,15 +2031,81 @@
hook.obj->metaObject()->method(hook.midx).signature(),
qPrintable(qerror.name()), qPrintable(qerror.message()));
Q_ASSERT(false);
+ } else {
+ // Successfully connected the signal
+ // Do we need to watch for this name?
+ if (shouldWatchService(hook.service)) {
+ WatchedServicesHash::Iterator it = watchedServiceNames.find(hook.service);
+ if (it != watchedServiceNames.end()) {
+ // already watching
+ ++it.value();
+ } else {
+ // we need to watch for this service changing
+ QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
+ connectSignal(dbusServerService, dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
+ QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+ this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ }
+ }
}
}
}
+bool QDBusConnectionPrivate::disconnectSignal(const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ QString name2 = name;
+ if (name2.isNull())
+ name2.detach();
+
+ hook.signature = signature;
+ if (!prepareHook(hook, key, service, QString(), path, interface, name, argumentMatch, receiver, slot, 0, false))
+ return false; // don't disconnect
+
+ // avoid duplicating:
+ QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
+ QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ //entry.owner == hook.owner &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // no need to compare the parameters if it's the same slot
+ disconnectSignal(it);
+ return true; // it was there
+ }
+ }
+
+ // the slot was not found
+ return false;
+}
+
QDBusConnectionPrivate::SignalHookHash::Iterator
QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
{
const SignalHook &hook = it.value();
+ WatchedServicesHash::Iterator sit = watchedServiceNames.find(hook.service);
+ if (sit != watchedServiceNames.end()) {
+ if (sit.value() == 1) {
+ watchedServiceNames.erase(sit);
+ QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS);
+ disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS),
+ QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+ this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ } else {
+ --sit.value();
+ }
+ }
+
bool erase = false;
MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
if (i == matchRefCounts.end()) {
@@ -2027,7 +2164,7 @@
SignalHook hook;
QString key;
- if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal,
+ if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal,
QDBusAbstractInterface::staticMetaObject.methodCount(), true))
return; // don't connect
@@ -2059,7 +2196,7 @@
SignalHook hook;
QString key;
- if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal,
+ if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal,
QDBusAbstractInterface::staticMetaObject.methodCount(), true))
return; // don't connect