390 |
390 |
391 } // extern "C" |
391 } // extern "C" |
392 |
392 |
393 static QByteArray buildMatchRule(const QString &service, const QString & /*owner*/, |
393 static QByteArray buildMatchRule(const QString &service, const QString & /*owner*/, |
394 const QString &objectPath, const QString &interface, |
394 const QString &objectPath, const QString &interface, |
395 const QString &member, const QString & /*signature*/) |
395 const QString &member, const QStringList &argMatch, const QString & /*signature*/) |
396 { |
396 { |
397 QString result = QLatin1String("type='signal',"); |
397 QString result = QLatin1String("type='signal',"); |
398 QString keyValue = QLatin1String("%1='%2',"); |
398 QString keyValue = QLatin1String("%1='%2',"); |
399 |
399 |
400 if (!service.isEmpty()) |
400 if (!service.isEmpty()) |
403 result += keyValue.arg(QLatin1String("path"), objectPath); |
403 result += keyValue.arg(QLatin1String("path"), objectPath); |
404 if (!interface.isEmpty()) |
404 if (!interface.isEmpty()) |
405 result += keyValue.arg(QLatin1String("interface"), interface); |
405 result += keyValue.arg(QLatin1String("interface"), interface); |
406 if (!member.isEmpty()) |
406 if (!member.isEmpty()) |
407 result += keyValue.arg(QLatin1String("member"), member); |
407 result += keyValue.arg(QLatin1String("member"), member); |
|
408 |
|
409 // add the argument string-matching now |
|
410 if (!argMatch.isEmpty()) { |
|
411 keyValue = QLatin1String("arg%1='%2',"); |
|
412 for (int i = 0; i < argMatch.count(); ++i) |
|
413 if (!argMatch.at(i).isNull()) |
|
414 result += keyValue.arg(i).arg(argMatch.at(i)); |
|
415 } |
408 |
416 |
409 result.chop(1); // remove ending comma |
417 result.chop(1); // remove ending comma |
410 return result.toLatin1(); |
418 return result.toLatin1(); |
411 } |
419 } |
412 |
420 |
919 : QObject(p), ref(1), mode(InvalidMode), connection(0), server(0), busService(0), |
932 : QObject(p), ref(1), mode(InvalidMode), connection(0), server(0), busService(0), |
920 watchAndTimeoutLock(QMutex::Recursive), |
933 watchAndTimeoutLock(QMutex::Recursive), |
921 rootNode(QString(QLatin1Char('/'))) |
934 rootNode(QString(QLatin1Char('/'))) |
922 { |
935 { |
923 static const bool threads = q_dbus_threads_init_default(); |
936 static const bool threads = q_dbus_threads_init_default(); |
924 static const int debugging = ::isDebugging = qgetenv("QDBUS_DEBUG").toInt(); |
937 static const int debugging = qgetenv("QDBUS_DEBUG").toInt(); |
|
938 ::isDebugging = debugging; |
925 Q_UNUSED(threads) |
939 Q_UNUSED(threads) |
926 Q_UNUSED(debugging) |
940 Q_UNUSED(debugging) |
927 |
941 |
928 #ifdef QDBUS_THREAD_DEBUG |
942 #ifdef QDBUS_THREAD_DEBUG |
929 if (debugging > 1) |
943 if (debugging > 1) |
1163 } |
1175 } |
1164 |
1176 |
1165 void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name, |
1177 void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name, |
1166 const QString &oldOwner, const QString &newOwner) |
1178 const QString &oldOwner, const QString &newOwner) |
1167 { |
1179 { |
1168 if (oldOwner == baseService) |
1180 Q_UNUSED(oldOwner); |
1169 unregisterService(name); |
|
1170 if (newOwner == baseService) |
|
1171 registerService(name); |
|
1172 |
|
1173 QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this); |
1181 QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this); |
1174 QMutableHashIterator<QString, SignalHook> it(signalHooks); |
1182 QMutableHashIterator<QString, SignalHook> it(signalHooks); |
1175 it.toFront(); |
1183 it.toFront(); |
1176 while (it.hasNext()) |
1184 while (it.hasNext()) |
1177 if (it.next().value().service == name) |
1185 if (it.next().value().service == name) |
1193 } |
1201 } |
1194 |
1202 |
1195 bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key, |
1203 bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key, |
1196 const QString &service, const QString &owner, |
1204 const QString &service, const QString &owner, |
1197 const QString &path, const QString &interface, const QString &name, |
1205 const QString &path, const QString &interface, const QString &name, |
|
1206 const QStringList &argMatch, |
1198 QObject *receiver, const char *signal, int minMIdx, |
1207 QObject *receiver, const char *signal, int minMIdx, |
1199 bool buildSignature) |
1208 bool buildSignature) |
1200 { |
1209 { |
1201 QByteArray normalizedName = signal + 1; |
1210 QByteArray normalizedName = signal + 1; |
1202 hook.midx = findSlot(receiver, signal + 1, hook.params); |
1211 hook.midx = findSlot(receiver, signal + 1, hook.params); |
1212 |
1221 |
1213 hook.service = service; |
1222 hook.service = service; |
1214 hook.owner = owner; // we don't care if the service has an owner yet |
1223 hook.owner = owner; // we don't care if the service has an owner yet |
1215 hook.path = path; |
1224 hook.path = path; |
1216 hook.obj = receiver; |
1225 hook.obj = receiver; |
|
1226 hook.argumentMatch = argMatch; |
1217 |
1227 |
1218 // build the D-Bus signal name and signature |
1228 // build the D-Bus signal name and signature |
1219 // This should not happen for QDBusConnection::connect, use buildSignature here, since |
1229 // This should not happen for QDBusConnection::connect, use buildSignature here, since |
1220 // QDBusConnection::connect passes false and everything else uses true |
1230 // QDBusConnection::connect passes false and everything else uses true |
1221 QString mname = name; |
1231 QString mname = name; |
1233 for (int i = 1; i < hook.params.count(); ++i) |
1243 for (int i = 1; i < hook.params.count(); ++i) |
1234 if (hook.params.at(i) != QDBusMetaTypeId::message) |
1244 if (hook.params.at(i) != QDBusMetaTypeId::message) |
1235 hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) ); |
1245 hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) ); |
1236 } |
1246 } |
1237 |
1247 |
1238 hook.matchRule = buildMatchRule(service, owner, path, interface, mname, hook.signature); |
1248 hook.matchRule = buildMatchRule(service, owner, path, interface, mname, argMatch, hook.signature); |
1239 return true; // connect to this signal |
1249 return true; // connect to this signal |
1240 } |
1250 } |
1241 |
1251 |
1242 void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code) |
1252 void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code) |
1243 { |
1253 { |
1476 SignalHookHash::const_iterator end = signalHooks.constEnd(); |
1486 SignalHookHash::const_iterator end = signalHooks.constEnd(); |
1477 //qDebug("looking for: %s", path.toLocal8Bit().constData()); |
1487 //qDebug("looking for: %s", path.toLocal8Bit().constData()); |
1478 //qDBusDebug() << signalHooks.keys(); |
1488 //qDBusDebug() << signalHooks.keys(); |
1479 for ( ; it != end && it.key() == key; ++it) { |
1489 for ( ; it != end && it.key() == key; ++it) { |
1480 const SignalHook &hook = it.value(); |
1490 const SignalHook &hook = it.value(); |
1481 if (!hook.owner.isEmpty() && hook.owner != msg.service()) |
1491 if (!hook.owner.isNull() && hook.owner != msg.service()) |
1482 continue; |
1492 continue; |
1483 if (!hook.path.isEmpty() && hook.path != msg.path()) |
1493 if (!hook.path.isEmpty() && hook.path != msg.path()) |
1484 continue; |
1494 continue; |
1485 if (!hook.signature.isEmpty() && hook.signature != msg.signature()) |
1495 if (!hook.signature.isEmpty() && hook.signature != msg.signature()) |
1486 continue; |
1496 continue; |
1487 if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty()) |
1497 if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty()) |
1488 continue; |
1498 continue; |
|
1499 if (!hook.argumentMatch.isEmpty()) { |
|
1500 const QVariantList arguments = msg.arguments(); |
|
1501 if (hook.argumentMatch.size() > arguments.size()) |
|
1502 continue; |
|
1503 |
|
1504 bool matched = true; |
|
1505 for (int i = 0; i < hook.argumentMatch.size(); ++i) { |
|
1506 const QString ¶m = hook.argumentMatch.at(i); |
|
1507 if (param.isNull()) |
|
1508 continue; // don't try to match against this |
|
1509 if (param == arguments.at(i).toString()) |
|
1510 continue; // matched |
|
1511 matched = false; |
|
1512 break; |
|
1513 } |
|
1514 if (!matched) |
|
1515 continue; |
|
1516 } |
1489 |
1517 |
1490 activateSignal(hook, msg); |
1518 activateSignal(hook, msg); |
1491 } |
1519 } |
1492 } |
1520 } |
1493 |
1521 |
1618 return; |
1646 return; |
1619 } |
1647 } |
1620 |
1648 |
1621 baseService = QString::fromUtf8(service); |
1649 baseService = QString::fromUtf8(service); |
1622 } else { |
1650 } else { |
1623 qWarning("QDBusConnectionPrivate::SetConnection: Unable to get base service"); |
1651 qWarning("QDBusConnectionPrivate::setConnection: Unable to get base service"); |
1624 } |
1652 } |
|
1653 |
|
1654 QString busService = QLatin1String(DBUS_SERVICE_DBUS); |
|
1655 connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(), |
|
1656 this, SLOT(registerService(QString))); |
|
1657 connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(), |
|
1658 this, SLOT(unregisterService(QString))); |
|
1659 |
1625 |
1660 |
1626 q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0); |
1661 q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0); |
1627 |
1662 |
1628 //qDebug("base service: %s", service); |
1663 //qDebug("base service: %s", service); |
1629 |
1664 |
1931 } |
1966 } |
1932 |
1967 |
1933 return 1; |
1968 return 1; |
1934 } |
1969 } |
1935 |
1970 |
|
1971 bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &owner, |
|
1972 const QString &path, const QString &interface, const QString &name, |
|
1973 const QStringList &argumentMatch, const QString &signature, |
|
1974 QObject *receiver, const char *slot) |
|
1975 { |
|
1976 // check the slot |
|
1977 QDBusConnectionPrivate::SignalHook hook; |
|
1978 QString key; |
|
1979 QString name2 = name; |
|
1980 if (name2.isNull()) |
|
1981 name2.detach(); |
|
1982 |
|
1983 hook.signature = signature; |
|
1984 if (!prepareHook(hook, key, service, owner, path, interface, name, argumentMatch, receiver, slot, 0, false)) |
|
1985 return false; // don't connect |
|
1986 |
|
1987 // avoid duplicating: |
|
1988 QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key); |
|
1989 QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd(); |
|
1990 for ( ; it != end && it.key() == key; ++it) { |
|
1991 const QDBusConnectionPrivate::SignalHook &entry = it.value(); |
|
1992 if (entry.service == hook.service && |
|
1993 entry.owner == hook.owner && |
|
1994 entry.path == hook.path && |
|
1995 entry.signature == hook.signature && |
|
1996 entry.obj == hook.obj && |
|
1997 entry.midx == hook.midx) { |
|
1998 // no need to compare the parameters if it's the same slot |
|
1999 return true; // already there |
|
2000 } |
|
2001 } |
|
2002 |
|
2003 connectSignal(key, hook); |
|
2004 return true; |
|
2005 } |
|
2006 |
1936 void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook) |
2007 void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook) |
1937 { |
2008 { |
1938 signalHooks.insertMulti(key, hook); |
2009 signalHooks.insertMulti(key, hook); |
1939 connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)), |
2010 connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)), |
1940 Qt::DirectConnection); |
2011 Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection)); |
1941 |
2012 |
1942 MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule); |
2013 MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule); |
1943 |
2014 |
1944 if (it != matchRefCounts.end()) { // Match already present |
2015 if (it != matchRefCounts.end()) { // Match already present |
1945 it.value() = it.value() + 1; |
2016 it.value() = it.value() + 1; |
1958 "while connecting signal to %s::%s: %s (%s)", |
2029 "while connecting signal to %s::%s: %s (%s)", |
1959 hook.obj->metaObject()->className(), |
2030 hook.obj->metaObject()->className(), |
1960 hook.obj->metaObject()->method(hook.midx).signature(), |
2031 hook.obj->metaObject()->method(hook.midx).signature(), |
1961 qPrintable(qerror.name()), qPrintable(qerror.message())); |
2032 qPrintable(qerror.name()), qPrintable(qerror.message())); |
1962 Q_ASSERT(false); |
2033 Q_ASSERT(false); |
1963 } |
2034 } else { |
1964 } |
2035 // Successfully connected the signal |
|
2036 // Do we need to watch for this name? |
|
2037 if (shouldWatchService(hook.service)) { |
|
2038 WatchedServicesHash::Iterator it = watchedServiceNames.find(hook.service); |
|
2039 if (it != watchedServiceNames.end()) { |
|
2040 // already watching |
|
2041 ++it.value(); |
|
2042 } else { |
|
2043 // we need to watch for this service changing |
|
2044 QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS); |
|
2045 connectSignal(dbusServerService, dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS), |
|
2046 QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), |
|
2047 this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); |
|
2048 } |
|
2049 } |
|
2050 } |
|
2051 } |
|
2052 } |
|
2053 |
|
2054 bool QDBusConnectionPrivate::disconnectSignal(const QString &service, |
|
2055 const QString &path, const QString &interface, const QString &name, |
|
2056 const QStringList &argumentMatch, const QString &signature, |
|
2057 QObject *receiver, const char *slot) |
|
2058 { |
|
2059 // check the slot |
|
2060 QDBusConnectionPrivate::SignalHook hook; |
|
2061 QString key; |
|
2062 QString name2 = name; |
|
2063 if (name2.isNull()) |
|
2064 name2.detach(); |
|
2065 |
|
2066 hook.signature = signature; |
|
2067 if (!prepareHook(hook, key, service, QString(), path, interface, name, argumentMatch, receiver, slot, 0, false)) |
|
2068 return false; // don't disconnect |
|
2069 |
|
2070 // avoid duplicating: |
|
2071 QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key); |
|
2072 QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end(); |
|
2073 for ( ; it != end && it.key() == key; ++it) { |
|
2074 const QDBusConnectionPrivate::SignalHook &entry = it.value(); |
|
2075 if (entry.service == hook.service && |
|
2076 //entry.owner == hook.owner && |
|
2077 entry.path == hook.path && |
|
2078 entry.signature == hook.signature && |
|
2079 entry.obj == hook.obj && |
|
2080 entry.midx == hook.midx) { |
|
2081 // no need to compare the parameters if it's the same slot |
|
2082 disconnectSignal(it); |
|
2083 return true; // it was there |
|
2084 } |
|
2085 } |
|
2086 |
|
2087 // the slot was not found |
|
2088 return false; |
1965 } |
2089 } |
1966 |
2090 |
1967 QDBusConnectionPrivate::SignalHookHash::Iterator |
2091 QDBusConnectionPrivate::SignalHookHash::Iterator |
1968 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it) |
2092 QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it) |
1969 { |
2093 { |
1970 const SignalHook &hook = it.value(); |
2094 const SignalHook &hook = it.value(); |
|
2095 |
|
2096 WatchedServicesHash::Iterator sit = watchedServiceNames.find(hook.service); |
|
2097 if (sit != watchedServiceNames.end()) { |
|
2098 if (sit.value() == 1) { |
|
2099 watchedServiceNames.erase(sit); |
|
2100 QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS); |
|
2101 disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS), |
|
2102 QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), |
|
2103 this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); |
|
2104 } else { |
|
2105 --sit.value(); |
|
2106 } |
|
2107 } |
1971 |
2108 |
1972 bool erase = false; |
2109 bool erase = false; |
1973 MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule); |
2110 MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule); |
1974 if (i == matchRefCounts.end()) { |
2111 if (i == matchRefCounts.end()) { |
1975 qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!"); |
2112 qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!"); |
2025 // this function is called by QDBusAbstractInterface when one of its signals is connected |
2162 // this function is called by QDBusAbstractInterface when one of its signals is connected |
2026 // we set up a relay from D-Bus into it |
2163 // we set up a relay from D-Bus into it |
2027 SignalHook hook; |
2164 SignalHook hook; |
2028 QString key; |
2165 QString key; |
2029 |
2166 |
2030 if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal, |
2167 if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal, |
2031 QDBusAbstractInterface::staticMetaObject.methodCount(), true)) |
2168 QDBusAbstractInterface::staticMetaObject.methodCount(), true)) |
2032 return; // don't connect |
2169 return; // don't connect |
2033 |
2170 |
2034 // add it to our list: |
2171 // add it to our list: |
2035 QDBusWriteLocker locker(ConnectRelayAction, this); |
2172 QDBusWriteLocker locker(ConnectRelayAction, this); |
2057 // this function is called by QDBusAbstractInterface when one of its signals is disconnected |
2194 // this function is called by QDBusAbstractInterface when one of its signals is disconnected |
2058 // we remove relay from D-Bus into it |
2195 // we remove relay from D-Bus into it |
2059 SignalHook hook; |
2196 SignalHook hook; |
2060 QString key; |
2197 QString key; |
2061 |
2198 |
2062 if (!prepareHook(hook, key, service, owner, path, interface, QString(), receiver, signal, |
2199 if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal, |
2063 QDBusAbstractInterface::staticMetaObject.methodCount(), true)) |
2200 QDBusAbstractInterface::staticMetaObject.methodCount(), true)) |
2064 return; // don't connect |
2201 return; // don't connect |
2065 |
2202 |
2066 // remove it from our list: |
2203 // remove it from our list: |
2067 QDBusWriteLocker locker(DisconnectRelayAction, this); |
2204 QDBusWriteLocker locker(DisconnectRelayAction, this); |