[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