[Telepathy-commits] [telepathy-qt4/master] Make Channel do autointrospect of the main interface state (with fallbacks, currently exposing Interfaces)
Olli Salli
olli.salli at collabora.co.uk
Sat Sep 20 10:00:55 PDT 2008
---
TelepathyQt4/cli-channel.cpp | 138 +++++++++++++++++++++++++++++++++++++++++-
TelepathyQt4/cli-channel.h | 63 +++++++++++++++++++
2 files changed, 200 insertions(+), 1 deletions(-)
diff --git a/TelepathyQt4/cli-channel.cpp b/TelepathyQt4/cli-channel.cpp
index 1fe04ce..520f497 100644
--- a/TelepathyQt4/cli-channel.cpp
+++ b/TelepathyQt4/cli-channel.cpp
@@ -25,6 +25,12 @@
#include "_gen/cli-channel.moc.hpp"
#include "cli-channel.moc.hpp"
+#include <QQueue>
+
+#include "cli-dbus.h"
+#include "constants.h"
+#include "debug.hpp"
+
namespace Telepathy
{
namespace Client
@@ -35,9 +41,88 @@ struct Channel::Private
// Public object
Channel& parent;
+ // Optional interface proxies
+ DBus::PropertiesInterface properties;
+
+ // Introspection
+ Readiness readiness;
+ QStringList interfaces;
+ QQueue<void (Private::*)()> introspectQueue;
+
Private(Channel& parent)
- : parent(parent)
+ : parent(parent),
+ properties(parent)
+ {
+ readiness = ReadinessJustCreated;
+
+ introspectQueue.enqueue(&Private::introspectMain);
+ continueIntrospection();
+
+ debug() << "Created new Channel";
+ }
+
+ void introspectMain()
+ {
+ debug() << "Calling Properties::GetAll(Channel)";
+ QDBusPendingCallWatcher* watcher =
+ new QDBusPendingCallWatcher(
+ properties.GetAll(TELEPATHY_INTERFACE_CHANNEL), &parent);
+ parent.connect(watcher,
+ SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(gotMainProperties(QDBusPendingCallWatcher*)));
+ }
+
+ void introspectMainFallbackInterfaces()
{
+ debug() << "Calling Channel::GetInterfaces()";
+ QDBusPendingCallWatcher* watcher =
+ new QDBusPendingCallWatcher(parent.GetInterfaces(), &parent);
+ parent.connect(watcher,
+ SIGNAL(finished(QDBusPendingCallWatcher*)),
+ SLOT(gotInterfaces(QDBusPendingCallWatcher*)));
+ }
+
+ void continueIntrospection()
+ {
+ if (introspectQueue.isEmpty()) {
+ if (readiness < ReadinessFull)
+ changeReadiness(ReadinessFull);
+ } else {
+ (this->*introspectQueue.dequeue())();
+ }
+ }
+
+ void nowHaveInterfaces()
+ {
+ debug() << "Channel has" << interfaces.size() << "optional interfaces:" << interfaces;
+
+ for (QStringList::const_iterator i = interfaces.begin();
+ i != interfaces.end();
+ ++i) {
+ // Enqueue introspection of any optional interfaces here
+ }
+
+ continueIntrospection();
+ }
+
+ void changeReadiness(Readiness newReadiness)
+ {
+ Q_ASSERT(newReadiness != readiness);
+
+ switch (readiness) {
+ case ReadinessJustCreated:
+ break;
+ case ReadinessFull:
+ Q_ASSERT(newReadiness == ReadinessDead);
+ break;
+ case ReadinessDead:
+ Q_ASSERT(false);
+ break;
+ }
+
+ debug() << "Channel readiness changed from" << readiness << "to" << newReadiness;
+ readiness = newReadiness;
+ emit parent.readinessChanged(newReadiness);
}
};
@@ -63,5 +148,56 @@ Channel::~Channel()
delete mPriv;
}
+Channel::Readiness Channel::readiness() const
+{
+ return mPriv->readiness;
+}
+
+QStringList Channel::interfaces() const
+{
+ return mPriv->interfaces;
+}
+
+void Channel::gotMainProperties(QDBusPendingCallWatcher* watcher)
+{
+ QDBusPendingReply<QVariantMap> reply = *watcher;
+ QVariantMap props;
+
+ if (!reply.isError())
+ props = reply.value();
+
+ if (props.size() < 4 || !props.contains("Interfaces")) {
+ if (reply.isError())
+ warning().nospace() << "Properties::GetAll(Channel) failed with " << reply.error().name() << ": " << reply.error().message();
+ else
+ warning() << "Reply to Properties::GetAll(Channel) didn't contain the expected properties";
+ warning() << "Assuming a pre-0.17.7-spec service, falling back to serial inspection";
+
+ mPriv->introspectQueue.enqueue(&Private::introspectMainFallbackInterfaces);
+ mPriv->continueIntrospection();
+ return;
+ }
+
+ debug() << "Got reply to Properties::GetAll(Channel)";
+ mPriv->interfaces = qdbus_cast<QStringList>(props.value("Interfaces"));
+ mPriv->nowHaveInterfaces();
+}
+
+void Channel::gotInterfaces(QDBusPendingCallWatcher* watcher)
+{
+ QDBusPendingReply<QStringList> reply = *watcher;
+
+ if (reply.isError()) {
+ warning().nospace() << "Channel::GetInterfaces() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
+ if (mPriv->readiness != ReadinessDead)
+ mPriv->changeReadiness(ReadinessDead);
+ return;
+ }
+
+ debug() << "Got reply to fallback Channel::GetInterfaces()";
+ mPriv->interfaces = reply.value();
+ mPriv->nowHaveInterfaces();
+}
+
}
}
diff --git a/TelepathyQt4/cli-channel.h b/TelepathyQt4/cli-channel.h
index 5bb343e..8e088d9 100644
--- a/TelepathyQt4/cli-channel.h
+++ b/TelepathyQt4/cli-channel.h
@@ -57,9 +57,43 @@ namespace Client
class Channel : public ChannelInterface
{
Q_OBJECT
+ Q_ENUMS(Readiness)
public:
/**
+ * Describes readiness of the Channel for usage. The readiness depends on
+ * the state of the remote object. In suitable states, an asynchronous
+ * introspection process is started, and the Channel becomes more ready when
+ * that process is completed.
+ */
+ enum Readiness {
+ /**
+ * The object has just been created and introspection is still in
+ * progress. No functionality is available.
+ *
+ * The readiness can change to any other state depending on the result
+ * of the initial state query to the remote object.
+ */
+ ReadinessJustCreated,
+
+ /**
+ * The remote object is alive and all introspection has been completed.
+ * Most functionality is available.
+ *
+ * The readiness can change to ReadinessDead.
+ */
+ ReadinessFull,
+
+ /**
+ * The remote object has gone into a state where it can no longer be
+ * used. No functionality is available.
+ *
+ * No further readiness changes are possible.
+ */
+ ReadinessDead
+ };
+
+ /**
* Creates a Channel associated with the given object on the session bus.
*
* \param serviceName Name of the service the object is on.
@@ -88,6 +122,35 @@ public:
*/
~Channel();
+ /**
+ * Returns the current readiness of the Channel.
+ *
+ * \return The readiness, as defined in #Readiness.
+ */
+ Readiness readiness() const;
+
+ /**
+ * Returns a list of optional interfaces implemented by the remote object.
+ * The contents of the list are undefined unless the Channel has readiness
+ * #ReadinessFull. The returned value stays constant for the entire lifetime
+ * of the Channel after reaching full readiness.
+ *
+ * \return D-Bus names of the supported interfaces.
+ */
+ QStringList interfaces() const;
+
+Q_SIGNALS:
+ /**
+ * Emitted whenever the readiness of the Channel changes.
+ *
+ * \param newReadiness The new readiness, as defined in #Readiness.
+ */
+ void readinessChanged(Telepathy::Client::Channel::Readiness newReadiness);
+
+private Q_SLOTS:
+ void gotMainProperties(QDBusPendingCallWatcher* watcher);
+ void gotInterfaces(QDBusPendingCallWatcher* watcher);
+
private:
struct Private;
friend struct Private;
--
1.5.6.5
More information about the Telepathy-commits
mailing list