[gnome-shell/message-tray: 3/5] Reorganize a bit, fix missing-first-message bug



commit 56d2691c314d6a7e05a8eb59a87b2054672bdf6f
Author: Dan Winship <danw gnome org>
Date:   Wed Oct 28 15:30:26 2009 -0400

    Reorganize a bit, fix missing-first-message bug
    
    https://bugzilla.gnome.org/show_bug.cgi?id=599193

 js/ui/messaging.js |  140 ++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 103 insertions(+), 37 deletions(-)
---
diff --git a/js/ui/messaging.js b/js/ui/messaging.js
index 190d6e6..9c4be52 100644
--- a/js/ui/messaging.js
+++ b/js/ui/messaging.js
@@ -1,6 +1,11 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
 const DBus = imports.dbus;
+const Lang = imports.lang;
 const Shell = imports.gi.Shell;
 
+const AVATAR_SIZE = 24;
+
 const TELEPATHY = "org.freedesktop.Telepathy.";
 const CONN = TELEPATHY + "Connection";
 const CHANNEL = TELEPATHY + "Channel";
@@ -24,7 +29,10 @@ const ClientObserverIface = {
 };
 
 const ConnectionIface = {
-    name: CONN
+    name: CONN,
+    signals: [
+        { name: 'StatusChanged', inSignature: 'u' }
+    ]
 };
 
 const ConnectionAvatarsIface = {
@@ -71,6 +79,12 @@ DBus.proxifyPrototype(Channel.prototype, ChannelIface);
 
 const ChannelTextIface = {
     name: CHANNELTEXT,
+    methods: [
+        { name: 'ListPendingMessages',
+          inSignature: 'b',
+          outSignature: 'a(uuuuus)'
+        }
+    ],
     signals: [
         { name: 'Received', inSignature: 'uuuuus' }
     ]
@@ -107,6 +121,8 @@ Messaging.prototype = {
         DBus.session.acquire_name(name, DBus.SINGLE_INSTANCE,
             function(name){log("Acquired name " + name);},
             function(name){log("Lost name " + name);});
+
+        this._conns = {};
     },
 
     get Interfaces() {
@@ -122,47 +138,97 @@ Messaging.prototype = {
     ObserveChannels: function(account, conn_path, channels,
                               dispatch_operation, requests_satisfied,
                               observer_info) {
-        log('observing ' + conn_path);
-        let conn = new Connection(conn_path);
-        let conn_name = conn_path.substr(1).replace('/','.','g');
-
-        for (var i = 0; i < channels.length; i++) {
-            let path = channels[i][0];
-            let props = channels[i][1];
-
-            let targethandle = props[CHANNEL + '.TargetHandle'];
-            let targetid = props[CHANNEL + '.TargetID'];
-
-            // conn.RequestAvatarRemote(targethandle,
-            //     function(result, excp) {
-            //         log("called for " + targetid);
-            //         let avatar;
-            //         if (result) {
-            //             let bytes = result[0];
-            //             avatar = Shell.TextureCache.get_default().load_from_data(bytes, bytes.length, -1, TRAY_HEIGHT);
-            //         } else {
-            //             // fallback avatar
-            //             avatar = Shell.TextureCache.get_default().load_icon_name("stock_person", TRAY_HEIGHT);
-            //         }
-	    // 	});
-
-            let channel = new Channel(conn_name, path);
-            let id = channel.connect('Closed',
-		function(emitter) {
-                    log('closed');
-                    channel.disconnect(id);
-                });
-
-            let text = new ChannelText(conn_name, path);
-	    text.connect('Received',
-		function(chan, id, timestamp, sender, type, flags, text) {
-		    log('Received: id ' + id + ', time ' + timestamp + ', sender ' + sender + ', type ' + type + ', flags ' + flags + ': ' + text);
-		});
+        let conn = this._conns[conn_path];
+        if (!conn) {
+            conn = new Connection(conn_path);
+            conn.connect('StatusChanged', Lang.bind(this, this._connectionStatusChanged));
+        }
+
+        let conn_name = nameify(conn_path);
+        for (let i = 0; i < channels.length; i++) {
+            new Source(conn, conn_name, channels[i][0], channels[i][1]);
         }
 
         return [true];
+    },
+
+    _connectionStatusChanged: function(connection, status) {
+        if (status == Connection_Status.Disconnected) {
+            delete this._conns[connection.getPath()];
+        }
     }
 };
 
 DBus.conformExport(Messaging.prototype, ClientIface);
 DBus.conformExport(Messaging.prototype, ClientObserverIface);
+
+function Source(conn, conn_name, channel_path, channel_props) {
+    this._init(conn, conn_name, channel_path, channel_props);
+}
+
+Source.prototype = {
+    _init: function(conn, conn_name, channel_path, channel_props) {
+        this._targetId = channel_props[CHANNEL + '.TargetID'];
+
+        log('channel for ' + this._targetId);
+
+	this._pendingMessages = null;
+
+	// FIXME: RequestAvatar is deprecated in favor of
+	// RequestAvatars; but RequestAvatars provides no explicit
+	// indication of "no avatar available", so there's no way we
+	// can reliably wait for it to finish before displaying a
+	// message. So we use RequestAvatar() instead.
+        let targethandle = channel_props[CHANNEL + '.TargetHandle'];
+        conn.RequestAvatarRemote(targethandle, Lang.bind(this, this._gotAvatar));
+
+        this._channel = new Channel(conn_name, channel_path);
+        this._closedId = this._channel.connect('Closed', Lang.bind(this, this._channelClosed));
+
+        this._channelText = new ChannelText(conn_name, channel_path);
+        this._receivedId = this._channelText.connect('Received', Lang.bind(this, this._receivedMessage));
+
+        this._channelText.ListPendingMessagesRemote(false,
+            Lang.bind(this, function(msgs, excp) {
+                if (msgs) {
+		    log('got pending messages for ' + this._targetId);
+		    this._pendingMessages = msgs;
+		    this._processPendingMessages();
+		}
+	    }));
+    },
+
+    _gotAvatar: function(result, excp) {
+        if (result) {
+            let bytes = result[0];
+            this._avatar = Shell.TextureCache.get_default().load_from_data(bytes, bytes.length, AVATAR_SIZE, AVATAR_SIZE);
+	    log('got avatar for ' + this._targetId);
+        } else {
+            // fallback avatar (FIXME)
+            this._avatar = Shell.TextureCache.get_default().load_icon_name("stock_person", AVATAR_SIZE);
+	    log('using default avatar for ' + this._targetId);
+        }
+
+        this._processPendingMessages();
+    },
+
+    _processPendingMessages: function() {
+	if (!this._avatar || !this._pendingMessages)
+	    return;
+
+        for (let i = 0; i < this._pendingMessages.length; i++)
+            this._receivedMessage.apply(this, [this._channel].concat(this._pendingMessages[i]));
+	this._pendingMessages = null;
+    },
+
+    _channelClosed: function() {
+        log('closed');
+        this._channel.disconnect(this._closedId);
+        this._channelText.disconnect(this._receivedId);
+    },
+
+    _receivedMessage: function(channel, id, timestamp, sender,
+                               type, flags, text) {
+        log('Received: id ' + id + ', time ' + timestamp + ', sender ' + sender + ', type ' + type + ', flags ' + flags + ': ' + text);
+    }
+};



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]