[geary/wip/765516-gtk-widget-conversation-viewer: 87/107] Reenable displaying sender avatars using Gravatar.



commit c380cd0e4aecc6b0e651ffe371feb1c1038d6655
Author: Michael James Gratton <mike vee net>
Date:   Fri Apr 22 14:55:40 2016 +1000

    Reenable displaying sender avatars using Gravatar.
    
    Since we're no longer using the web view to display the user avatar, use
    libsoup and add some additional infrastructure to support caching the
    avatars. Also switches to HTTPS for accessing the Gravatar service.
    
    * src/client/application/geary-application.vala
      (GearyApplication::get_user_cache_directory): New method to return the
      XDG cache directory for Geary.
    
    * src/client/application/geary-controller.vala: Add both a Soup session
      and cache for fetching avatars. Write the cache to disk on controller
      close.
    
    * src/client/conversation-viewer/conversation-email.vala
      (ConversationEmail::start_loading): Trigger avatar loads when loading
      the email.
    
    * src/client/conversation-viewer/conversation-message.vala: Replace
      single avatar image widget with two, so the image does not need to be
      rescaled when expanded/collapsed.
    
    * src/client/conversation-viewer/conversation-message.vala
      (ConversationMessage::load_avatar): Queue a request for a Gravatar
      avatar.
      (ConversationMessage::set_avatar): Load pixbuf returned by Gravatar,
      scale and set it for the preview and expanded avatar images.
    
    * src/client/conversation-viewer/conversation-viewer.vala
      (ConversationViewer::clear): Cancel any outsanding avatar loads.
    
    * src/client/util/util-gravatar.vala (Gravatar): Construct a HTTPS URL to
      avoid advertising to the NSA who we are receiving email from.
    
    * ui/conversation-message.ui: Add the second avatar image.

 src/client/application/geary-application.vala      |    6 +-
 src/client/application/geary-controller.vala       |   28 +-
 .../conversation-viewer/conversation-email.vala    |    8 +
 .../conversation-viewer/conversation-message.vala  |   68 +++-
 .../conversation-viewer/conversation-viewer.vala   |    7 +-
 src/client/util/util-gravatar.vala                 |    2 +-
 ui/conversation-message.ui                         |  500 +++++++++++---------
 7 files changed, 377 insertions(+), 242 deletions(-)
---
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index 64038bb..65f787e 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -221,7 +221,11 @@ public class GearyApplication : Gtk.Application {
     public File get_user_data_directory() {
         return File.new_for_path(Environment.get_user_data_dir()).get_child("geary");
     }
-    
+
+    public File get_user_cache_directory() {
+        return File.new_for_path(Environment.get_user_cache_dir()).get_child("geary");
+    }
+
     public File get_user_config_directory() {
         return File.new_for_path(Environment.get_user_config_dir()).get_child("geary");
     }
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 2b9b38b..4264a90 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -97,7 +97,10 @@ public class GearyController : Geary.BaseObject {
     public AutostartManager? autostart_manager { get; private set; default = null; }
     
     public LoginDialog? login_dialog { get; private set; default = null; }
-    
+
+    public Soup.Session? avatar_session { get; private set; default = null; }
+    private Soup.Cache? avatar_cache = null;
+
     private Geary.Account? current_account = null;
     private Gee.HashMap<Geary.Account, Geary.App.EmailStore> email_stores
         = new Gee.HashMap<Geary.Account, Geary.App.EmailStore>();
@@ -190,7 +193,22 @@ public class GearyController : Geary.BaseObject {
         // Create DB upgrade dialog.
         upgrade_dialog = new UpgradeDialog();
         upgrade_dialog.notify[UpgradeDialog.PROP_VISIBLE_NAME].connect(display_main_window_if_ready);
-        
+
+        // Use a global avatar session because a cache must be used
+        // per-session, and we don't want to have to load the cache
+        // for each conversation load.
+        File avatar_cache_dir = GearyApplication.instance.get_user_cache_directory()
+            .get_child("avatar_cache");
+        avatar_cache = new Soup.Cache(
+            avatar_cache_dir.get_path(),
+            Soup.CacheType.SINGLE_USER
+        );
+        avatar_cache.set_max_size(4 * 1024 * 1024); // 4MB
+        avatar_session = new Soup.Session.with_options(
+            Soup.SESSION_USER_AGENT, "Geary/" + GearyApplication.VERSION
+        );
+        avatar_session.add_feature(avatar_cache);
+
         // Create the main window (must be done after creating actions.)
         main_window = new MainWindow(GearyApplication.instance);
         main_window.on_shift_key.connect(on_shift_key);
@@ -347,7 +365,11 @@ public class GearyController : Geary.BaseObject {
         }
         
         main_window.destroy();
-        
+
+        debug("Flushing avatar cache...");
+        avatar_cache.flush();
+        avatar_cache.dump();
+
         // Turn off the lights and lock the door behind you
         try {
             debug("Closing Engine...");
diff --git a/src/client/conversation-viewer/conversation-email.vala 
b/src/client/conversation-viewer/conversation-email.vala
index e93111b..af40dc4 100644
--- a/src/client/conversation-viewer/conversation-email.vala
+++ b/src/client/conversation-viewer/conversation-email.vala
@@ -145,8 +145,16 @@ public class ConversationEmail : Gtk.Box {
     }
 
     public async void start_loading(Cancellable load_cancelled) {
+        yield primary_message.load_avatar(
+            GearyApplication.instance.controller.avatar_session,
+            load_cancelled
+        );
         yield primary_message.load_message_body(load_cancelled);
         foreach (ConversationMessage message in conversation_messages) {
+            yield message.load_avatar(
+                GearyApplication.instance.controller.avatar_session,
+                load_cancelled
+            );
             yield message.load_message_body(load_cancelled);
         }
         yield load_attachments(load_cancelled);
diff --git a/src/client/conversation-viewer/conversation-message.vala 
b/src/client/conversation-viewer/conversation-message.vala
index 8c03097..a630ec6 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -67,11 +67,10 @@ public class ConversationMessage : Gtk.Box {
     public Gtk.Box infobar_box; // not yet supported: { get; private set; }
 
     [GtkChild]
-    private Gtk.Image avatar_image;
-
-    [GtkChild]
     private Gtk.Revealer preview_revealer;
     [GtkChild]
+    private Gtk.Image preview_avatar;
+    [GtkChild]
     private Gtk.Label from_preview;
     [GtkChild]
     private Gtk.Label body_preview;
@@ -79,6 +78,8 @@ public class ConversationMessage : Gtk.Box {
     [GtkChild]
     private Gtk.Revealer header_revealer;
     [GtkChild]
+    private Gtk.Image header_avatar;
+    [GtkChild]
     private Gtk.Box from_header;
     [GtkChild]
     private Gtk.Box to_header;
@@ -183,8 +184,6 @@ public class ConversationMessage : Gtk.Box {
     }
 
     public void show_message_body(bool include_transitions=true) {
-        avatar_image.set_pixel_size(32); // XXX constant
-
         Gtk.RevealerTransitionType revealer = preview_revealer.get_transition_type();
         if (!include_transitions) {
             preview_revealer.set_transition_type(Gtk.RevealerTransitionType.NONE);
@@ -208,12 +207,34 @@ public class ConversationMessage : Gtk.Box {
     }
 
     public void hide_message_body() {
-        avatar_image.set_pixel_size(24); // XXX constant
         preview_revealer.set_reveal_child(true);
         header_revealer.set_reveal_child(false);
         body_revealer.set_reveal_child(false);
     }
 
+    public async void load_avatar(Soup.Session session, Cancellable load_cancellable) {
+        // Queued messages are cancelled in ConversationViewer.clear()
+        // rather than here using a callback on load_cancellable since
+        // we don't have per-message control using
+        // Soup.Session.queue_message.
+        Geary.RFC822.MailboxAddress? primary = message.get_primary_originator();
+        if (primary != null) {
+            int window_scale = get_window().get_scale_factor();
+            int pixel_size = header_avatar.get_pixel_size();
+            Soup.Message message = new Soup.Message(
+                "GET",
+                Gravatar.get_image_uri(
+                    primary, Gravatar.Default.NOT_FOUND, pixel_size * window_scale
+                )
+            );
+            session.queue_message(message, (session, message) => {
+                    if (message.status_code == 200) {
+                        set_avatar(message.response_body.data);
+                    }
+                });
+        }
+    }
+
     public async void load_message_body(Cancellable load_cancelled) {
         bool remote_images = false;
         bool load_images = false;
@@ -293,6 +314,41 @@ public class ConversationMessage : Gtk.Box {
         header.set_visible(true);
     }
 
+    private void set_avatar(uint8[] image_data) {
+        Gdk.Pixbuf avatar = null;
+        Gdk.PixbufLoader loader = new Gdk.PixbufLoader();
+        try {
+            loader.write(image_data);
+            loader.close();
+            avatar = loader.get_pixbuf();
+        } catch (Error err) {
+            debug("Error loading Gravatar response: %s", err.message);
+        }
+
+        if (avatar != null) {
+            Gdk.Window window = get_window();
+            int window_scale = window.get_scale_factor();
+            int preview_size = preview_avatar.pixel_size * window_scale;
+            preview_avatar.set_from_surface(
+                Gdk.cairo_surface_create_from_pixbuf(
+                    avatar.scale_simple(
+                        preview_size, preview_size, Gdk.InterpType.BILINEAR
+                    ),
+                    window_scale,
+                    window)
+            );
+            int header_size = header_avatar.pixel_size * window_scale;
+            if (avatar.width != header_size) {
+                avatar = avatar.scale_simple(
+                    header_size, header_size, Gdk.InterpType.BILINEAR
+                );
+            }
+            header_avatar.set_from_surface(
+                Gdk.cairo_surface_create_from_pixbuf(avatar, window_scale, window)
+            );
+        }
+    }
+
     // This delegate is called from within Geary.RFC822.Message.get_body while assembling the plain
     // or HTML document when a non-text MIME part is encountered within a multipart/mixed container.
     // If this returns null, the MIME part is dropped from the final returned document; otherwise,
diff --git a/src/client/conversation-viewer/conversation-viewer.vala 
b/src/client/conversation-viewer/conversation-viewer.vala
index 46258fb..bb433e3 100644
--- a/src/client/conversation-viewer/conversation-viewer.vala
+++ b/src/client/conversation-viewer/conversation-viewer.vala
@@ -348,9 +348,14 @@ public class ConversationViewer : Gtk.Stack {
         debug("Showing child: %s\n", widget.get_name());
         base.set_visible_child(widget);
     }
-    
+
     // Removes all displayed e-mails from the view.
     private void clear() {
+        // Cancel any pending avatar loads here, rather than in
+        // ConversationMessage using a Cancellable callback since we
+        // don't have per-message control of it when using
+        // Soup.Session.queue_message.
+        GearyApplication.instance.controller.avatar_session.flush_queue();
         foreach (Gtk.Widget child in conversation_listbox.get_children()) {
             conversation_listbox.remove(child);
         }
diff --git a/src/client/util/util-gravatar.vala b/src/client/util/util-gravatar.vala
index c221ced..a5f099e 100644
--- a/src/client/util/util-gravatar.vala
+++ b/src/client/util/util-gravatar.vala
@@ -56,7 +56,7 @@ public string get_image_uri(Geary.RFC822.MailboxAddress addr, Default def, int s
     // Gravatar spec for preparing address and hashing:
     // http://en.gravatar.com/site/implement/hash/
     string md5 = Checksum.compute_for_string(ChecksumType.MD5, addr.address.strip().down());
-    
+
     return "https://secure.gravatar.com/avatar/%s?d=%s&s=%d".printf(md5, def.to_param(), size);
 }
 
diff --git a/ui/conversation-message.ui b/ui/conversation-message.ui
index e1596e3..1028d0c 100644
--- a/ui/conversation-message.ui
+++ b/ui/conversation-message.ui
@@ -11,23 +11,7 @@
       <object class="GtkBox" id="summary_box">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="spacing">8</property>
-        <child>
-          <object class="GtkImage" id="avatar_image">
-            <property name="width_request">18</property>
-            <property name="height_request">18</property>
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="valign">start</property>
-            <property name="pixel_size">24</property>
-            <property name="icon_name">avatar-default-symbolic</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
+        <property name="spacing">6</property>
         <child>
           <object class="GtkBox">
             <property name="visible">True</property>
@@ -43,88 +27,34 @@
                   <object class="GtkBox">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="orientation">vertical</property>
+                    <property name="spacing">6</property>
                     <child>
-                      <object class="GtkLabel" id="from_preview">
+                      <object class="GtkImage" id="preview_avatar">
+                        <property name="width_request">18</property>
+                        <property name="height_request">18</property>
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="halign">start</property>
-                        <property name="label" translatable="yes">From &lt;email&gt;</property>
-                        <property name="ellipsize">end</property>
-                        <style>
-                          <class name="header-value"/>
-                        </style>
+                        <property name="valign">start</property>
+                        <property name="pixel_size">32</property>
+                        <property name="icon_name">avatar-default-symbolic</property>
                       </object>
                       <packing>
-                        <property name="expand">True</property>
-                        <property name="fill">True</property>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="body_preview">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="halign">start</property>
-                        <property name="label" translatable="yes">Preview body text.</property>
-                        <property name="ellipsize">end</property>
-                        <style>
-                          <class name="preview-value"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="expand">True</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkRevealer" id="header_revealer">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="transition_type">none</property>
-                <child>
-                  <object class="GtkBox" id="header_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="orientation">vertical</property>
-                    <child>
-                      <object class="GtkBox" id="from_header">
+                      <object class="GtkBox">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
                         <child>
-                          <object class="GtkLabel" id="from_label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">From:</property>
-                            <property name="xalign">1</property>
-                            <style>
-                              <class name="header-label"/>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="from_text">
+                          <object class="GtkLabel" id="from_preview">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="halign">start</property>
                             <property name="label" translatable="yes">From &lt;email&gt;</property>
-                            <property name="selectable">True</property>
                             <property name="ellipsize">end</property>
                             <style>
                               <class name="header-value"/>
@@ -133,44 +63,19 @@
                           <packing>
                             <property name="expand">True</property>
                             <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox" id="to_header">
-                        <property name="can_focus">False</property>
-                        <child>
-                          <object class="GtkLabel" id="to_label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">To:</property>
-                            <property name="xalign">1</property>
-                            <style>
-                              <class name="header-label"/>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
                             <property name="position">0</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkLabel" id="to_text">
+                          <object class="GtkLabel" id="body_preview">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="halign">start</property>
-                            <property name="label" translatable="yes">To &lt;email&gt;</property>
-                            <property name="selectable">True</property>
+                            <property name="label" translatable="yes">Preview body text.</property>
                             <property name="ellipsize">end</property>
+                            <style>
+                              <class name="preview-value"/>
+                            </style>
                           </object>
                           <packing>
                             <property name="expand">True</property>
@@ -178,9 +83,6 @@
                             <property name="position">1</property>
                           </packing>
                         </child>
-                        <style>
-                          <class name="empty"/>
-                        </style>
                       </object>
                       <packing>
                         <property name="expand">False</property>
@@ -188,64 +90,85 @@
                         <property name="position">1</property>
                       </packing>
                     </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRevealer" id="header_revealer">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="transition_type">none</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="spacing">6</property>
                     <child>
-                      <object class="GtkBox" id="cc_header">
+                      <object class="GtkImage" id="header_avatar">
+                        <property name="width_request">18</property>
+                        <property name="height_request">18</property>
+                        <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <child>
-                          <object class="GtkLabel" id="cc_label">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">Cc:</property>
-                            <property name="xalign">1</property>
-                            <style>
-                              <class name="header-label"/>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="fill">True</property>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="cc_text">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="halign">start</property>
-                            <property name="label" translatable="yes">CC &lt;email&gt;</property>
-                            <property name="selectable">True</property>
-                            <property name="ellipsize">end</property>
-                          </object>
-                          <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                        <style>
-                          <class name="empty"/>
-                        </style>
+                        <property name="valign">start</property>
+                        <property name="pixel_size">48</property>
+                        <property name="icon_name">avatar-default-symbolic</property>
                       </object>
                       <packing>
                         <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkBox" id="bcc_header">
+                      <object class="GtkBox" id="header_box">
+                        <property name="visible">True</property>
                         <property name="can_focus">False</property>
+                        <property name="orientation">vertical</property>
                         <child>
-                          <object class="GtkLabel" id="bcc_label">
+                          <object class="GtkBox" id="from_header">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">Bcc:</property>
-                            <property name="xalign">1</property>
-                            <style>
-                              <class name="header-label"/>
-                              <class name="dim-label"/>
-                            </style>
+                            <child>
+                              <object class="GtkLabel" id="from_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">From:</property>
+                                <property name="xalign">1</property>
+                                <style>
+                                  <class name="header-label"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="from_text">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">From &lt;email&gt;</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                                <style>
+                                  <class name="header-value"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
@@ -254,118 +177,235 @@
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkLabel" id="bcc_text">
-                            <property name="visible">True</property>
+                          <object class="GtkBox" id="to_header">
                             <property name="can_focus">False</property>
-                            <property name="halign">start</property>
-                            <property name="label" translatable="yes">BCC &lt;email&gt;</property>
-                            <property name="selectable">True</property>
-                            <property name="ellipsize">end</property>
+                            <child>
+                              <object class="GtkLabel" id="to_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">To:</property>
+                                <property name="xalign">1</property>
+                                <style>
+                                  <class name="header-label"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="to_text">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">To &lt;email&gt;</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <style>
+                              <class name="empty"/>
+                            </style>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
+                            <property name="expand">False</property>
                             <property name="fill">True</property>
                             <property name="position">1</property>
                           </packing>
                         </child>
-                        <style>
-                          <class name="empty"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">3</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox" id="subject_header">
-                        <property name="can_focus">False</property>
                         <child>
-                          <object class="GtkLabel" id="subject_label">
-                            <property name="visible">True</property>
+                          <object class="GtkBox" id="cc_header">
                             <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">Subject:</property>
-                            <property name="xalign">1</property>
+                            <child>
+                              <object class="GtkLabel" id="cc_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Cc:</property>
+                                <property name="xalign">1</property>
+                                <style>
+                                  <class name="header-label"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="cc_text">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">CC &lt;email&gt;</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
                             <style>
-                              <class name="header-label"/>
-                              <class name="dim-label"/>
+                              <class name="empty"/>
                             </style>
                           </object>
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">0</property>
+                            <property name="position">2</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkLabel" id="subject_text">
-                            <property name="visible">True</property>
+                          <object class="GtkBox" id="bcc_header">
                             <property name="can_focus">False</property>
-                            <property name="halign">start</property>
-                            <property name="label" translatable="yes">Subject</property>
-                            <property name="selectable">True</property>
-                            <property name="ellipsize">end</property>
+                            <child>
+                              <object class="GtkLabel" id="bcc_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Bcc:</property>
+                                <property name="xalign">1</property>
+                                <style>
+                                  <class name="header-label"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="bcc_text">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">BCC &lt;email&gt;</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <style>
+                              <class name="empty"/>
+                            </style>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
+                            <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">1</property>
+                            <property name="position">3</property>
                           </packing>
                         </child>
-                        <style>
-                          <class name="empty"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">4</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkBox" id="date_header">
-                        <property name="can_focus">False</property>
                         <child>
-                          <object class="GtkLabel" id="date_label">
-                            <property name="visible">True</property>
+                          <object class="GtkBox" id="subject_header">
                             <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">Date:</property>
-                            <property name="xalign">1</property>
+                            <child>
+                              <object class="GtkLabel" id="subject_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Subject:</property>
+                                <property name="xalign">1</property>
+                                <style>
+                                  <class name="header-label"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="subject_text">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">Subject</property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
                             <style>
-                              <class name="header-label"/>
-                              <class name="dim-label"/>
+                              <class name="empty"/>
                             </style>
                           </object>
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">0</property>
+                            <property name="position">4</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkLabel" id="date_text">
-                            <property name="visible">True</property>
+                          <object class="GtkBox" id="date_header">
                             <property name="can_focus">False</property>
-                            <property name="halign">start</property>
-                            <property name="label" translatable="yes">1/1/1970 </property>
-                            <property name="selectable">True</property>
-                            <property name="ellipsize">end</property>
+                            <child>
+                              <object class="GtkLabel" id="date_label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Date:</property>
+                                <property name="xalign">1</property>
+                                <style>
+                                  <class name="header-label"/>
+                                  <class name="dim-label"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="date_text">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="halign">start</property>
+                                <property name="label" translatable="yes">1/1/1970     </property>
+                                <property name="selectable">True</property>
+                                <property name="ellipsize">end</property>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <style>
+                              <class name="empty"/>
+                            </style>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
+                            <property name="expand">False</property>
                             <property name="fill">True</property>
-                            <property name="position">1</property>
+                            <property name="position">5</property>
                           </packing>
                         </child>
-                        <style>
-                          <class name="empty"/>
-                        </style>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">True</property>
-                        <property name="position">5</property>
+                        <property name="position">1</property>
                       </packing>
                     </child>
                   </object>
@@ -381,7 +421,7 @@
           <packing>
             <property name="expand">True</property>
             <property name="fill">True</property>
-            <property name="position">1</property>
+            <property name="position">0</property>
           </packing>
         </child>
       </object>



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