[Telepathy-commits] [telepathy-qt4/master] Connection: Added support for features (Aliasing, Presence and SimplePresence).
Andre Moreira Magalhaes (andrunko)
andre.magalhaes at collabora.co.uk
Sat Jan 24 18:20:08 PST 2009
---
TelepathyQt4/Client/connection.cpp | 206 +++++++++++++++++++++++++++---------
TelepathyQt4/Client/connection.h | 3 +
2 files changed, 160 insertions(+), 49 deletions(-)
diff --git a/TelepathyQt4/Client/connection.cpp b/TelepathyQt4/Client/connection.cpp
index e5378d0..fe03b58 100644
--- a/TelepathyQt4/Client/connection.cpp
+++ b/TelepathyQt4/Client/connection.cpp
@@ -77,6 +77,8 @@ struct Connection::Private
void changeReadiness(Readiness newReadiness);
+ void updatePendingOperations();
+
struct HandleContext;
class PendingReady;
@@ -91,7 +93,8 @@ struct Connection::Private
ConnectionInterfacePresenceInterface *presence;
DBus::PropertiesInterface *properties;
- PendingReady *pendingReady;
+ bool ready;
+ QList<PendingReady *> pendingOperations;
// Introspection
bool initialIntrospection;
@@ -99,6 +102,10 @@ struct Connection::Private
QStringList interfaces;
QQueue<void (Private::*)()> introspectQueue;
+ Connection::Features features;
+ Connection::Features pendingFeatures;
+ Connection::Features missingFeatures;
+
// Introspected properties
uint status;
uint statusReason;
@@ -146,11 +153,14 @@ class Connection::Private::PendingReady : public PendingOperation
friend class Connection;
public:
- PendingReady(Connection *parent);
+ PendingReady(Connection::Features features, QObject *parent);
+
+ Connection::Features features;
};
-Connection::Private::PendingReady::PendingReady(Connection *parent)
- : PendingOperation(parent)
+Connection::Private::PendingReady::PendingReady(Connection::Features features, QObject *parent)
+ : PendingOperation(parent),
+ features(features)
{
}
@@ -161,7 +171,6 @@ Connection::Private::Private(Connection *parent)
aliasing(0),
presence(0),
properties(0),
- pendingReady(0),
initialIntrospection(false),
readiness(ReadinessJustCreated),
status(ConnectionStatusDisconnected),
@@ -340,6 +349,20 @@ void Connection::Private::changeReadiness(Readiness newReadiness)
emit parent->readinessChanged(newReadiness);
}
+void Connection::Private::updatePendingOperations()
+{
+ foreach (Private::PendingReady *operation, pendingOperations) {
+ if (ready &&
+ ((operation->features &
+ (features | missingFeatures)) == operation->features)) {
+ operation->setFinished();
+ }
+ if (operation->isFinished()) {
+ pendingOperations.removeOne(operation);
+ }
+ }
+}
+
QMap<QPair<QString, QString>, Connection::Private::HandleContext*> Connection::Private::handleContexts;
QMutex Connection::Private::handleContextsLock;
@@ -546,11 +569,17 @@ QStringList Connection::interfaces() const
*/
uint Connection::aliasFlags() const
{
- if (mPriv->readiness != ReadinessFull) {
- warning() << "Connection::aliasFlags() used with readiness" << mPriv->readiness << "!= ReadinessFull";
+ if (mPriv->missingFeatures & FeatureAliasing) {
+ warning() << "Trying to retrieve aliasFlags from connection, but "
+ "aliasing is not supported";
+ }
+ else if (!(mPriv->features & FeatureAliasing)) {
+ warning() << "Trying to retrieve aliasFlags from connection without "
+ "calling Connection::becomeReady(FeatureAliasing)";
}
- else if (!interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_ALIASING)) {
- warning() << "Connection::aliasFlags() used without the remote object supporting the Aliasing interface";
+ else if (mPriv->pendingFeatures & FeatureAliasing) {
+ warning() << "Trying to retrieve aliasFlags from connection, but "
+ "aliasing is still being retrieved";
}
return mPriv->aliasFlags;
@@ -568,12 +597,17 @@ uint Connection::aliasFlags() const
*/
StatusSpecMap Connection::presenceStatuses() const
{
- if (mPriv->readiness != ReadinessFull) {
- warning() << "Connection::presenceStatuses() used with readiness" <<
- mPriv->readiness << "!= ReadinessFull";
+ if (mPriv->missingFeatures & FeaturePresence) {
+ warning() << "Trying to retrieve presence from connection, but "
+ "presence is not supported";
}
- else if (!interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_PRESENCE)) {
- warning() << "Connection::presenceStatuses() used without the remote object supporting the Presence interface";
+ else if (!(mPriv->features & FeaturePresence)) {
+ warning() << "Trying to retrieve presence from connection without "
+ "calling Connection::becomeReady(FeaturePresence)";
+ }
+ else if (mPriv->pendingFeatures & FeaturePresence) {
+ warning() << "Trying to retrieve presence from connection, but "
+ "presence is still being retrieved";
}
return mPriv->presenceStatuses;
@@ -596,13 +630,17 @@ StatusSpecMap Connection::presenceStatuses() const
*/
SimpleStatusSpecMap Connection::simplePresenceStatuses() const
{
- if (mPriv->readiness != ReadinessNotYetConnected &&
- mPriv->readiness != ReadinessFull) {
- warning() << "Connection::simplePresenceStatuses() used with readiness"
- << mPriv->readiness << "not in (ReadinessNotYetConnected, ReadinessFull)";
+ if (mPriv->missingFeatures & FeatureSimplePresence) {
+ warning() << "Trying to retrieve simple presence from connection, but "
+ "simple presence is not supported";
+ }
+ else if (!(mPriv->features & FeatureSimplePresence)) {
+ warning() << "Trying to retrieve simple presence from connection without "
+ "calling Connection::becomeReady(FeatureSimplePresence)";
}
- else if (!interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)) {
- warning() << "Connection::simplePresenceStatuses() used without the remote object supporting the SimplePresence interface";
+ else if (mPriv->pendingFeatures & FeatureSimplePresence) {
+ warning() << "Trying to retrieve simple presence from connection, but "
+ "simple presence is still being retrieved";
}
return mPriv->simplePresenceStatuses;
@@ -843,8 +881,26 @@ void Connection::gotInterfaces(QDBusPendingCallWatcher *watcher)
QDBusPendingReply<QStringList> reply = *watcher;
if (!reply.isError()) {
- mPriv->interfaces = reply.value();
+ debug() << "Connection basic functionality is ready";
+ mPriv->ready = true;
debug() << "Got reply to GetInterfaces():" << mPriv->interfaces;
+ mPriv->interfaces = reply.value();
+
+ // queue introspection of all optional features and add the feature to
+ // pendingFeatures so we don't queue up the introspect func for the feature
+ // again on becomeReady.
+ if (mPriv->interfaces.contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_ALIASING)) {
+ mPriv->introspectQueue.enqueue(&Private::introspectAliasing);
+ mPriv->pendingFeatures |= FeatureAliasing;
+ }
+ if (mPriv->interfaces.contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_PRESENCE)) {
+ mPriv->introspectQueue.enqueue(&Private::introspectPresence);
+ mPriv->pendingFeatures |= FeaturePresence;
+ }
+ if (mPriv->interfaces.contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)) {
+ mPriv->introspectQueue.enqueue(&Private::introspectSimplePresence);
+ mPriv->pendingFeatures |= FeatureSimplePresence;
+ }
}
else {
warning().nospace() << "GetInterfaces() failed with" <<
@@ -852,24 +908,6 @@ void Connection::gotInterfaces(QDBusPendingCallWatcher *watcher)
"- assuming no new interfaces";
}
- foreach (const QString &interface, mPriv->interfaces) {
- void (Private::*introspectFunc)() = 0;
-
- if (interface == TELEPATHY_INTERFACE_CONNECTION_INTERFACE_ALIASING) {
- introspectFunc = &Private::introspectAliasing;
- }
- else if (interface == TELEPATHY_INTERFACE_CONNECTION_INTERFACE_PRESENCE) {
- introspectFunc = &Private::introspectPresence;
- }
- else if (interface == TELEPATHY_INTERFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE) {
- introspectFunc = &Private::introspectSimplePresence;
- }
-
- if (introspectFunc) {
- mPriv->introspectQueue.enqueue(introspectFunc);
- }
- }
-
continueIntrospection();
watcher->deleteLater();
@@ -879,11 +917,19 @@ void Connection::gotAliasFlags(QDBusPendingCallWatcher *watcher)
{
QDBusPendingReply<uint> reply = *watcher;
+ mPriv->pendingFeatures &= ~FeatureAliasing;
+
if (!reply.isError()) {
+ mPriv->features |= FeatureAliasing;
+ debug() << "Adding FeatureAliasing to features";
+
mPriv->aliasFlags = static_cast<ConnectionAliasFlag>(reply.value());
debug().nospace() << "Got alias flags 0x" << hex << mPriv->aliasFlags;
}
else {
+ mPriv->missingFeatures |= FeatureAliasing;
+ debug() << "Adding FeatureAliasing to missing features";
+
warning().nospace() << "GetAliasFlags() failed with" <<
reply.error().name() << ":" << reply.error().message();
}
@@ -897,11 +943,20 @@ void Connection::gotStatuses(QDBusPendingCallWatcher *watcher)
{
QDBusPendingReply<StatusSpecMap> reply = *watcher;
+ mPriv->pendingFeatures &= ~FeaturePresence;
+
if (!reply.isError()) {
+ mPriv->features |= FeaturePresence;
+ debug() << "Adding FeaturePresence to features";
+
mPriv->presenceStatuses = reply.value();
debug() << "Got" << mPriv->presenceStatuses.size() << "legacy presence statuses";
}
else {
+ mPriv->missingFeatures |= FeaturePresence;
+ debug() << "Adding FeaturePresence to missing features";
+
+
warning().nospace() << "GetStatuses() failed with" <<
reply.error().name() << ":" << reply.error().message();
}
@@ -915,11 +970,19 @@ void Connection::gotSimpleStatuses(QDBusPendingCallWatcher *watcher)
{
QDBusPendingReply<QDBusVariant> reply = *watcher;
+ mPriv->pendingFeatures &= ~FeatureSimplePresence;
+
if (!reply.isError()) {
+ mPriv->features |= FeatureSimplePresence;
+ debug() << "Adding FeatureSimplePresence to features";
+
mPriv->simplePresenceStatuses = qdbus_cast<SimpleStatusSpecMap>(reply.value().variant());
debug() << "Got" << mPriv->simplePresenceStatuses.size() << "simple presence statuses";
}
else {
+ mPriv->missingFeatures |= FeatureSimplePresence;
+ debug() << "Adding FeatureSimplePresence to missing features";
+
warning().nospace() << "Getting simple presence statuses failed with" <<
reply.error().name() << ":" << reply.error().message();
}
@@ -1130,7 +1193,8 @@ PendingHandles *Connection::referenceHandles(uint handleType, const UIntList &ha
*/
bool Connection::isReady(Features features) const
{
- return mPriv->readiness == ReadinessFull;
+ return mPriv->ready
+ && ((mPriv->features & features) == features);
}
/**
@@ -1148,11 +1212,43 @@ PendingOperation *Connection::becomeReady(Features requestedFeatures)
return new PendingSuccess(this);
}
- if (!mPriv->pendingReady) {
- mPriv->pendingReady = new Private::PendingReady(this);
+ debug() << "Calling becomeReady with requested features:"
+ << requestedFeatures;
+ foreach (Private::PendingReady *operation, mPriv->pendingOperations) {
+ if (operation->features == requestedFeatures) {
+ debug() << "Returning cached pending operation";
+ return operation;
+ }
}
- return mPriv->pendingReady;
+ Feature optionalFeatures[3] = { FeatureAliasing, FeaturePresence, FeatureSimplePresence };
+ Feature optionalFeature;
+ for (uint i = 0; i < sizeof(optionalFeatures) / sizeof(Feature); ++i) {
+ optionalFeature = optionalFeatures[i];
+
+ if (requestedFeatures & optionalFeature) {
+ // as the feature is optional, if it's know to not be supported,
+ // just finish silently
+ if (requestedFeatures == (int) optionalFeature &&
+ mPriv->missingFeatures & optionalFeature) {
+ return new PendingSuccess(this);
+ }
+
+ // don't enqueue introspect funcs here, as they will be enqueued
+ // when possible, depending on readiness, e.g. introspectMain needs
+ // to be called before introspectAliasing, ...
+ }
+ }
+
+ mPriv->pendingFeatures |= requestedFeatures;
+
+ debug() << "Creating new pending operation";
+ Private::PendingReady *operation =
+ new Private::PendingReady(requestedFeatures, this);
+ mPriv->pendingOperations.append(operation);
+
+ mPriv->updatePendingOperations();
+ return operation;
}
/**
@@ -1255,17 +1351,27 @@ void Connection::continueIntrospection()
if (mPriv->introspectQueue.isEmpty()) {
if (mPriv->initialIntrospection) {
mPriv->initialIntrospection = false;
- if (mPriv->readiness < ReadinessNotYetConnected)
+ if (mPriv->readiness < ReadinessNotYetConnected) {
mPriv->changeReadiness(ReadinessNotYetConnected);
+ }
}
else {
if (mPriv->readiness != ReadinessDead) {
mPriv->changeReadiness(ReadinessFull);
-
- if (mPriv->pendingReady) {
- mPriv->pendingReady->setFinished();
- // it will delete itself later
- mPriv->pendingReady = 0;
+ // we should have all interfaces now, so if an interface is not
+ // present and we have a feature for it, add the feature to missing
+ // features.
+ if (!mPriv->interfaces.contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_ALIASING)) {
+ debug() << "adding FeatureAliasing to missing features";
+ mPriv->missingFeatures |= FeatureAliasing;
+ }
+ if (!mPriv->interfaces.contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_PRESENCE)) {
+ debug() << "adding FeaturePresence to missing features";
+ mPriv->missingFeatures |= FeaturePresence;
+ }
+ if (!mPriv->interfaces.contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE)) {
+ debug() << "adding FeatureSimplePresence to missing features";
+ mPriv->missingFeatures |= FeatureSimplePresence;
}
}
}
@@ -1273,6 +1379,8 @@ void Connection::continueIntrospection()
else {
(mPriv->*(mPriv->introspectQueue.dequeue()))();
}
+
+ mPriv->updatePendingOperations();
}
}
diff --git a/TelepathyQt4/Client/connection.h b/TelepathyQt4/Client/connection.h
index 8b74911..148ade6 100644
--- a/TelepathyQt4/Client/connection.h
+++ b/TelepathyQt4/Client/connection.h
@@ -58,6 +58,9 @@ class Connection : public StatefulDBusProxy,
public:
enum Feature {
+ FeatureAliasing = 1,
+ FeaturePresence = 2,
+ FeatureSimplePresence = 4,
_Padding = 0xFFFFFFFF
};
Q_DECLARE_FLAGS(Features, Feature)
--
1.5.6.5
More information about the Telepathy-commits
mailing list