[evolution/wip/webkit2] Replace EAttachmentButton with a native HTML code and change the EAttachmentBar position



commit c8660c0a37918cf3edd96ec1a4736f9fd9cd39f9
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 1 23:57:39 2016 +0200

    Replace EAttachmentButton with a native HTML code and change the EAttachmentBar position
    
    No more EMailFormatterClass:get_widget(). There are new FIXME WK2,
    unfortunately, but to be done soon.

 data/org.gnome.evolution.mail.gschema.xml.in |    5 +
 e-util/Makefile.am                           |    2 -
 e-util/e-attachment-button.c                 |  929 ----------------------
 e-util/e-attachment-button.h                 |   95 ---
 e-util/e-attachment-store.c                  |   53 ++-
 e-util/e-attachment-store.h                  |   11 +
 e-util/e-stock-request.c                     |   35 +
 e-util/e-util.h                              |    1 -
 e-util/e-web-view.c                          |   97 +++
 e-util/e-web-view.h                          |   15 +
 em-format/Makefile.am                        |    4 -
 em-format/e-mail-formatter-attachment-bar.c  |  104 ---
 em-format/e-mail-formatter-attachment.c      |  246 ++----
 em-format/e-mail-formatter-audio.c           |    2 +-
 em-format/e-mail-formatter-extension.c       |   61 --
 em-format/e-mail-formatter-extension.h       |   11 -
 em-format/e-mail-formatter.c                 |   21 +-
 em-format/e-mail-formatter.h                 |    6 +-
 em-format/e-mail-parser-attachment-bar.c     |   78 --
 em-format/e-mail-parser-message.c            |    6 -
 em-format/e-mail-parser.c                    |    2 -
 em-format/e-mail-part-attachment-bar.c       |   98 ---
 em-format/e-mail-part-attachment-bar.h       |   70 --
 em-format/e-mail-part-attachment.h           |    2 +-
 em-format/e-mail-part-utils.c                |    5 +
 mail/e-mail-browser.c                        |   14 +
 mail/e-mail-display.c                        | 1083 +++++++++++---------------
 mail/e-mail-display.h                        |    9 +
 mail/e-mail-request.c                        |   91 +++
 modules/mail/e-mail-shell-content.c          |   57 ++-
 modules/mail/e-mail-shell-content.h          |    2 +
 modules/mail/e-mail-shell-view-actions.c     |   32 +
 modules/mail/e-mail-shell-view-actions.h     |    2 +
 po/POTFILES.in                               |    1 +
 ui/evolution-mail.ui                         |    1 +
 web-extensions/e-dom-utils.c                 |   51 +-
 web-extensions/e-web-extension.c             |  159 ++++
 37 files changed, 1161 insertions(+), 2300 deletions(-)
---
diff --git a/data/org.gnome.evolution.mail.gschema.xml.in b/data/org.gnome.evolution.mail.gschema.xml.in
index 24d18e0..7b90aa0 100644
--- a/data/org.gnome.evolution.mail.gschema.xml.in
+++ b/data/org.gnome.evolution.mail.gschema.xml.in
@@ -294,6 +294,11 @@
       <_summary>Timeout for marking messages as seen</_summary>
       <_description>Timeout in milliseconds for marking messages as seen.</_description>
     </key>
+    <key name="show-attachment-bar" type="b">
+      <default>true</default>
+      <_summary>Show Attachment Bar</_summary>
+      <_description>Show Attachment Bar below the message preview pane when the message has 
attachments.</_description>
+    </key>
     <key name="show-email" type="b">
       <default>false</default>
       <_summary>Sender email-address column in the message list</_summary>
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 40ae077..721e6b0 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -119,7 +119,6 @@ evolution_util_include_HEADERS =  \
        e-alert-sink.h \
        e-alert.h \
        e-attachment-bar.h \
-       e-attachment-button.h \
        e-attachment-dialog.h \
        e-attachment-handler-image.h \
        e-attachment-handler.h \
@@ -395,7 +394,6 @@ libevolution_util_la_SOURCES = \
        e-alert-sink.c \
        e-alert.c \
        e-attachment-bar.c \
-       e-attachment-button.c \
        e-attachment-dialog.c \
        e-attachment-handler-image.c \
        e-attachment-handler.c \
diff --git a/e-util/e-attachment-store.c b/e-util/e-attachment-store.c
index f0648db..ab6247d 100644
--- a/e-util/e-attachment-store.c
+++ b/e-util/e-attachment-store.c
@@ -53,6 +53,14 @@ enum {
        PROP_TOTAL_SIZE
 };
 
+enum {
+       ATTACHMENT_ADDED,
+       ATTACHMENT_REMOVED,
+       LAST_SIGNAL
+};
+
+static gulong signals[LAST_SIGNAL];
+
 G_DEFINE_TYPE (
        EAttachmentStore,
        e_attachment_store,
@@ -159,6 +167,22 @@ e_attachment_store_class_init (EAttachmentStoreClass *class)
                        G_MAXUINT64,
                        0,
                        G_PARAM_READABLE));
+
+       signals[ATTACHMENT_ADDED] = g_signal_new (
+               "attachment-added",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (EAttachmentStoreClass, attachment_added),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, E_TYPE_ATTACHMENT);
+
+       signals[ATTACHMENT_REMOVED] = g_signal_new (
+               "attachment-removed",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (EAttachmentStoreClass, attachment_removed),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, E_TYPE_ATTACHMENT);
 }
 
 static void
@@ -232,6 +256,8 @@ e_attachment_store_add_attachment (EAttachmentStore *store,
        g_object_notify (G_OBJECT (store), "num-attachments");
        g_object_notify (G_OBJECT (store), "total-size");
        g_object_thaw_notify (G_OBJECT (store));
+
+       g_signal_emit (store, signals[ATTACHMENT_ADDED], 0, attachment);
 }
 
 gboolean
@@ -243,6 +269,7 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
        GtkTreeModel *model;
        GtkTreePath *path;
        GtkTreeIter iter;
+       gboolean removed;
 
        g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), FALSE);
        g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
@@ -254,7 +281,8 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
                return FALSE;
 
        if (!gtk_tree_row_reference_valid (reference)) {
-               g_hash_table_remove (hash_table, attachment);
+               if (g_hash_table_remove (hash_table, attachment))
+                       g_signal_emit (store, signals[ATTACHMENT_REMOVED], 0, attachment);
                return FALSE;
        }
 
@@ -267,13 +295,16 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
        gtk_tree_path_free (path);
 
        gtk_list_store_remove (GTK_LIST_STORE (store), &iter);
-       g_hash_table_remove (hash_table, attachment);
+       removed = g_hash_table_remove (hash_table, attachment);
 
        g_object_freeze_notify (G_OBJECT (store));
        g_object_notify (G_OBJECT (store), "num-attachments");
        g_object_notify (G_OBJECT (store), "total-size");
        g_object_thaw_notify (G_OBJECT (store));
 
+       if (removed)
+               g_signal_emit (store, signals[ATTACHMENT_REMOVED], 0, attachment);
+
        return TRUE;
 }
 
@@ -307,6 +338,8 @@ e_attachment_store_remove_all (EAttachmentStore *store)
                e_attachment_set_reference (attachment, NULL);
 
                g_warn_if_fail (g_hash_table_remove (store->priv->attachment_index, attachment));
+
+               g_signal_emit (store, signals[ATTACHMENT_REMOVED], 0, attachment);
        }
 
        g_list_foreach (list, (GFunc) g_object_unref, NULL);
@@ -780,6 +813,22 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
        return destination;
 }
 
+gboolean
+e_attachment_store_transform_num_attachments_to_visible_boolean (GBinding *binding,
+                                                                const GValue *from_value,
+                                                                GValue *to_value,
+                                                                gpointer user_data)
+{
+       g_return_val_if_fail (from_value != NULL, FALSE);
+       g_return_val_if_fail (to_value != NULL, FALSE);
+       g_return_val_if_fail (G_VALUE_HOLDS_UINT (from_value), FALSE);
+       g_return_val_if_fail (G_VALUE_HOLDS_BOOLEAN (to_value), FALSE);
+
+       g_value_set_boolean (to_value, g_value_get_uint (from_value) != 0);
+
+       return TRUE;
+}
+
 /******************** e_attachment_store_get_uris_async() ********************/
 
 typedef struct _UriContext UriContext;
diff --git a/e-util/e-attachment-store.h b/e-util/e-attachment-store.h
index 584110c..2e68aa9 100644
--- a/e-util/e-attachment-store.h
+++ b/e-util/e-attachment-store.h
@@ -60,6 +60,12 @@ struct _EAttachmentStore {
 
 struct _EAttachmentStoreClass {
        GtkListStoreClass parent_class;
+
+       /* Signals */
+       void    (* attachment_added)    (EAttachmentStore *store,
+                                        EAttachment *attachment);
+       void    (* attachment_removed)  (EAttachmentStore *store,
+                                        EAttachment *attachment);
 };
 
 enum {
@@ -104,6 +110,11 @@ GFile *            e_attachment_store_run_save_dialog
                                                 GList *attachment_list,
                                                 GtkWindow *parent);
 
+gboolean       e_attachment_store_transform_num_attachments_to_visible_boolean
+                                               (GBinding *binding,
+                                                const GValue *from_value,
+                                                GValue *to_value,
+                                                gpointer user_data);
 /* Asynchronous Operations */
 void           e_attachment_store_get_uris_async
                                                (EAttachmentStore *store,
diff --git a/e-util/e-stock-request.c b/e-util/e-stock-request.c
index dac07ed..c550a2c 100644
--- a/e-util/e-stock-request.c
+++ b/e-util/e-stock-request.c
@@ -166,6 +166,41 @@ process_stock_request_idle_cb (gpointer user_data)
                        }
 
                        gtk_icon_info_free (icon_info);
+               } else if (g_strcmp0 (suri->host, "x-evolution-arrow-down") == 0) {
+                       GdkPixbuf *pixbuf;
+                       GdkRGBA rgba;
+                       guchar *data;
+                       gint stride;
+                       cairo_surface_t *surface;
+                       cairo_t *cr;
+
+                       stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, size);
+                       buff_len = stride * size;
+                       data = g_malloc0 (buff_len);
+                       surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24, size, size, 
stride);
+
+                       cr = cairo_create (surface);
+
+                       if (gtk_style_context_lookup_color (context, "color", &rgba))
+                               gdk_cairo_set_source_rgba (cr, &rgba);
+                       else
+                               cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
+
+                       gtk_render_background (context, cr, 0, 0, size, size);
+                       gtk_render_arrow (context, cr, G_PI, 0, 0, size);
+
+                       cairo_destroy (cr);
+
+                       cairo_surface_flush (surface);
+
+                       pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE, 8, size, size, 
stride, NULL, NULL);
+                       gdk_pixbuf_save_to_buffer (
+                               pixbuf, &buffer, &buff_len,
+                               "png", &local_error, NULL);
+                       g_object_unref (pixbuf);
+
+                       cairo_surface_destroy (surface);
+                       g_free (data);
                }
        }
 
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 25f0330..1e7b4fd 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -32,7 +32,6 @@
 #include <e-util/e-alert-sink.h>
 #include <e-util/e-alert.h>
 #include <e-util/e-attachment-bar.h>
-#include <e-util/e-attachment-button.h>
 #include <e-util/e-attachment-dialog.h>
 #include <e-util/e-attachment-handler-image.h>
 #include <e-util/e-attachment-handler.h>
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index 2020478..bebd007 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -4395,3 +4395,100 @@ e_web_view_unregister_element_clicked (EWebView *web_view,
                }
        }
 }
+
+void
+e_web_view_set_element_hidden (EWebView *web_view,
+                              const gchar *element_id,
+                              gboolean hidden)
+{
+       GDBusProxy *web_extension;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id && *element_id);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (!web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               web_extension,
+               "SetElementHidden",
+               g_variant_new (
+                       "(tsb)",
+                       webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+                       element_id,
+                       hidden),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+void
+e_web_view_set_element_style_property (EWebView *web_view,
+                                      const gchar *element_id,
+                                      const gchar *property_name,
+                                      const gchar *value,
+                                      const gchar *priority)
+{
+       GDBusProxy *web_extension;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id && *element_id);
+       g_return_if_fail (property_name && *property_name);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (!web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               web_extension,
+               "SetElementStyleProperty",
+               g_variant_new (
+                       "(tssss)",
+                       webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+                       element_id,
+                       property_name,
+                       value ? value : "",
+                       priority ? priority : ""),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
+
+void
+e_web_view_set_element_attribute (EWebView *web_view,
+                                 const gchar *element_id,
+                                 const gchar *namespace_uri,
+                                 const gchar *qualified_name,
+                                 const gchar *value)
+{
+       GDBusProxy *web_extension;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+       g_return_if_fail (element_id && *element_id);
+       g_return_if_fail (qualified_name && *qualified_name);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (!web_extension)
+               return;
+
+       g_dbus_proxy_call (
+               web_extension,
+               "SetElementAttribute",
+               g_variant_new (
+                       "(tssss)",
+                       webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+                       element_id,
+                       namespace_uri ? namespace_uri : "",
+                       qualified_name,
+                       value ? value : ""),
+               G_DBUS_CALL_FLAGS_NONE,
+               -1,
+               NULL,
+               NULL,
+               NULL);
+}
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index 73e3bcc..62203d2 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -276,6 +276,21 @@ void               e_web_view_unregister_element_clicked
                                                 const gchar *element_class,
                                                 EWebViewElementClickedFunc callback,
                                                 gpointer user_data);
+void           e_web_view_set_element_hidden   (EWebView *web_view,
+                                                const gchar *element_id,
+                                                gboolean hidden);
+void           e_web_view_set_element_style_property
+                                               (EWebView *web_view,
+                                                const gchar *element_id,
+                                                const gchar *property_name,
+                                                const gchar *value,
+                                                const gchar *priority);
+void           e_web_view_set_element_attribute
+                                               (EWebView *web_view,
+                                                const gchar *element_id,
+                                                const gchar *namespace_uri,
+                                                const gchar *qualified_name,
+                                                const gchar *value);
 G_END_DECLS
 
 #endif /* E_WEB_VIEW_H */
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index 8939280..ca80983 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -34,7 +34,6 @@ evolution_mail_formatter_include_HEADERS =            \
        e-mail-parser.h                                 \
        e-mail-part.h                                   \
        e-mail-part-attachment.h                        \
-       e-mail-part-attachment-bar.h                    \
        e-mail-part-audio.h                             \
        e-mail-part-headers.h                           \
        e-mail-part-image.h                             \
@@ -70,7 +69,6 @@ libevolution_mail_formatter_la_SOURCES =              \
        e-mail-formatter-quote.c                        \
        e-mail-formatter-utils.c                        \
        e-mail-formatter-attachment.c                   \
-       e-mail-formatter-attachment-bar.c               \
        e-mail-formatter-audio.c                        \
        e-mail-formatter-enumtypes.c                    \
        e-mail-formatter-error.c                        \
@@ -93,7 +91,6 @@ libevolution_mail_formatter_la_SOURCES =              \
        e-mail-parser-extension.c                       \
        e-mail-parser.c                                 \
        e-mail-parser-application-mbox.c                \
-       e-mail-parser-attachment-bar.c                  \
        e-mail-parser-audio.c                           \
        e-mail-parser-headers.c                         \
        e-mail-parser-image.c                           \
@@ -117,7 +114,6 @@ libevolution_mail_formatter_la_SOURCES =            \
        e-mail-parser-text-plain.c                      \
        e-mail-part.c                                   \
        e-mail-part-attachment.c                        \
-       e-mail-part-attachment-bar.c                    \
        e-mail-part-audio.c                             \
        e-mail-part-headers.c                           \
        e-mail-part-image.c                             \
diff --git a/em-format/e-mail-formatter-attachment.c b/em-format/e-mail-formatter-attachment.c
index 2a2f2c9..01109cd 100644
--- a/em-format/e-mail-formatter-attachment.c
+++ b/em-format/e-mail-formatter-attachment.c
@@ -26,7 +26,6 @@
 
 #include "e-mail-formatter-extension.h"
 #include "e-mail-inline-filter.h"
-#include "e-mail-part-attachment-bar.h"
 #include "e-mail-part-attachment.h"
 #include "e-mail-part-utils.h"
 
@@ -44,70 +43,10 @@ G_DEFINE_TYPE (
 
 static const gchar *formatter_mime_types[] = {
        E_MAIL_PART_ATTACHMENT_MIME_TYPE,
-       "application/vnd.evolution.widget.attachment-button",
+       "application/vnd.evolution.attachment-button",
        NULL
 };
 
-static EAttachmentStore *
-find_attachment_store (EMailPartList *part_list,
-                       EMailPart *start)
-{
-       EAttachmentStore *store = NULL;
-       GQueue queue = G_QUEUE_INIT;
-       GList *head, *link;
-       const gchar *start_id;
-       gchar *tmp, *pos;
-       EMailPart *part;
-       gchar *id;
-
-       start_id = e_mail_part_get_id (start);
-
-       e_mail_part_list_queue_parts (part_list, NULL, &queue);
-
-       head = g_queue_peek_head_link (&queue);
-
-       id = g_strconcat (start_id, ".attachment-bar", NULL);
-       tmp = g_strdup (id);
-       part = NULL;
-       do {
-               d (printf ("Looking up attachment bar as %s\n", id));
-
-               for (link = head; link != NULL; link = g_list_next (link)) {
-                       EMailPart *p = link->data;
-                       const gchar *p_id;
-
-                       p_id = e_mail_part_get_id (p);
-
-                       if (g_strcmp0 (p_id, id) == 0) {
-                               part = p;
-                               break;
-                       }
-               }
-
-               pos = g_strrstr (tmp, ".");
-               if (!pos)
-                       break;
-
-               g_free (id);
-               g_free (tmp);
-               tmp = g_strndup (start_id, pos - tmp);
-               id = g_strdup_printf ("%s.attachment-bar", tmp);
-
-       } while (pos && !part);
-
-       g_free (id);
-       g_free (tmp);
-
-       if (part != NULL)
-               store = e_mail_part_attachment_bar_get_store (
-                       E_MAIL_PART_ATTACHMENT_BAR (part));
-
-       while (!g_queue_is_empty (&queue))
-               g_object_unref (g_queue_pop_head (&queue));
-
-       return store;
-}
-
 static gboolean
 emfe_attachment_format (EMailFormatterExtension *extension,
                         EMailFormatter *formatter,
@@ -118,13 +57,16 @@ emfe_attachment_format (EMailFormatterExtension *extension,
 {
        gchar *text, *html;
        gchar *button_id;
-       EAttachmentStore *store;
        EMailExtensionRegistry *registry;
        GQueue *extensions;
        EMailPartAttachment *empa;
        CamelMimePart *mime_part;
        CamelMimeFilterToHTMLFlags flags;
+       GOutputStream *content_stream = NULL;
        GString *buffer;
+       gint icon_width, icon_height;
+       gchar *icon_uri;
+       gpointer attachment_ptr = NULL;
        const gchar *attachment_part_id;
        const gchar *part_id;
 
@@ -139,8 +81,8 @@ emfe_attachment_format (EMailFormatterExtension *extension,
                EAttachment *attachment;
                GList *head, *link;
 
-               attachment = e_mail_part_attachment_ref_attachment (
-                       E_MAIL_PART_ATTACHMENT (part));
+               attachment = e_mail_part_attachment_ref_attachment (E_MAIL_PART_ATTACHMENT (part));
+               attachment_ptr = attachment;
 
                head = g_queue_peek_head_link (&part->validities);
 
@@ -161,17 +103,9 @@ emfe_attachment_format (EMailFormatterExtension *extension,
                                        pair->validity->encrypt.status);
                }
 
-               store = find_attachment_store (context->part_list, part);
-               if (store) {
-                       GList *attachments = e_attachment_store_get_attachments (store);
-                       if (!g_list_find (attachments, attachment)) {
-                               e_attachment_store_add_attachment (
-                                       store, attachment);
-                       }
-                       g_list_free_full (attachments, g_object_unref);
-               } else {
-                       g_warning ("Failed to locate attachment-bar for %s", part_id);
-               }
+               e_attachment_set_shown (attachment, e_mail_part_should_show_inline (part));
+
+               e_mail_formatter_claim_attachment (formatter, attachment);
 
                g_object_unref (attachment);
        }
@@ -262,26 +196,12 @@ emfe_attachment_format (EMailFormatterExtension *extension,
 
        button_id = g_strconcat (attachment_part_id, ".attachment_button", NULL);
 
-       /* XXX Wild guess at the initial size. */
-       buffer = g_string_sized_new (8192);
-
-       g_string_append_printf (
-               buffer,
-               "<div class=\"attachment\">"
-               "<table width=\"100%%\" border=\"0\">"
-               "<tr valign=\"middle\">"
-               "<td align=\"left\" width=\"100\">"
-               "<object type=\"application/vnd.evolution.widget.attachment-button\" "
-               "height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>"
-               "</td>"
-               "<td align=\"left\">%s</td>"
-               "</tr>", part_id, button_id, html);
-
-       g_free (button_id);
-       g_free (html);
+       if (!gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, &icon_width, &icon_height)) {
+               icon_width = 16;
+               icon_height = 16;
+       }
 
        if (extensions != NULL) {
-               GOutputStream *content_stream;
                gboolean success = FALSE;
 
                content_stream = g_memory_output_stream_new_resizable ();
@@ -322,51 +242,85 @@ emfe_attachment_format (EMailFormatterExtension *extension,
                        }
                }
 
-               if (success) {
-                       gchar *wrapper_element_id;
-                       gconstpointer data;
-                       gsize size;
+               e_mail_part_attachment_set_expandable (empa, success);
+       }
 
-                       wrapper_element_id = g_strconcat (
-                               attachment_part_id, ".wrapper", NULL);
+       icon_uri = e_mail_part_build_uri (
+               e_mail_part_list_get_folder (context->part_list),
+               e_mail_part_list_get_message_uid (context->part_list),
+               "part_id", G_TYPE_STRING, part_id,
+               "attachment_icon", G_TYPE_POINTER, attachment_ptr,
+               "size", G_TYPE_INT, icon_width,
+               NULL);
 
-                       data = g_memory_output_stream_get_data (
-                               G_MEMORY_OUTPUT_STREAM (content_stream));
-                       size = g_memory_output_stream_get_data_size (
-                               G_MEMORY_OUTPUT_STREAM (content_stream));
+       /* XXX Wild guess at the initial size. */
+       buffer = g_string_sized_new (8192);
 
-                       g_string_append_printf (
-                               buffer,
-                               "<tr><td colspan=\"2\">"
-                               "<div class=\"attachment-wrapper\" id=\"%s\"",
-                               wrapper_element_id);
+       g_string_append_printf (
+               buffer,
+               "<div class=\"attachment\">"
+               "<table width=\"100%%\" border=\"0\">"
+               "<tr valign=\"middle\">"
+               "<td align=\"left\" width=\"1px\" style=\"white-space:pre;\">"
+               "<button type=\"button\" class=\"attachment-expander\" id=\"%s\" value=\"%p\" data=\"%s\" 
style=\"vertical-align:middle; margin:0px;\" %s>"
+               "<img id=\"attachment-expander-img-%p\" src=\"gtk-stock://%s?size=%d\" width=\"%dpx\" 
height=\"%dpx\" style=\"vertical-align:middle;\">"
+               "<img src=\"%s\" width=\"%dpx\" height=\"%dpx\" style=\"vertical-align:middle;\">"
+               "</button>"
+               "<button type=\"button\" class=\"attachment-menu\" id=\"%s\" value=\"%p\" 
style=\"vertical-align:middle; margin:0px;\">"
+               "<img src=\"gtk-stock://x-evolution-arrow-down?size=%d\" width=\"%dpx\" height=\"%dpx\" 
style=\"vertical-align:middle;\">"
+               "</button>"
+               "</td><td align=\"left\">%s</td></tr>",
+               part_id, attachment_ptr, html, e_mail_part_attachment_get_expandable (empa) ? "" : "disabled",
+               attachment_ptr, e_mail_part_should_show_inline (part) ? "go-down" : "go-next", 
GTK_ICON_SIZE_BUTTON, icon_width, icon_height,
+               icon_uri, icon_width, icon_height,
+               part_id, attachment_ptr, GTK_ICON_SIZE_BUTTON, icon_width, icon_height,
+               html);
+
+       g_free (icon_uri);
+       g_free (button_id);
+       g_free (html);
 
-                       if (e_mail_part_should_show_inline (part)) {
-                               g_string_append (buffer, ">");
-                               g_string_append_len (buffer, data, size);
-                       } else {
-                               gchar *inner_html_data;
+       if (content_stream && e_mail_part_attachment_get_expandable (empa)) {
+               gchar *wrapper_element_id;
+               gconstpointer data;
+               gsize size;
 
-                               inner_html_data = g_markup_escape_text (data, size);
+               wrapper_element_id = g_strdup_printf ("attachment-wrapper-%p", attachment_ptr);
 
-                               g_string_append_printf (
-                                       buffer,
-                                       " inner-html-data=\"%s\">",
-                                       inner_html_data);
+               data = g_memory_output_stream_get_data (
+                       G_MEMORY_OUTPUT_STREAM (content_stream));
+               size = g_memory_output_stream_get_data_size (
+                       G_MEMORY_OUTPUT_STREAM (content_stream));
 
-                               g_free (inner_html_data);
-                       }
+               g_string_append_printf (
+                       buffer,
+                       "<tr><td colspan=\"2\">"
+                       "<div class=\"attachment-wrapper\" id=\"%s\"",
+                       wrapper_element_id);
 
-                       g_string_append (buffer, "</div></td></tr>");
+               if (e_mail_part_should_show_inline (part)) {
+                       g_string_append (buffer, ">");
+                       g_string_append_len (buffer, data, size);
+               } else {
+                       gchar *inner_html_data;
 
-                       e_mail_part_attachment_set_expandable (empa, TRUE);
+                       inner_html_data = g_markup_escape_text (data, size);
 
-                       g_free (wrapper_element_id);
+                       g_string_append_printf (
+                               buffer,
+                               " inner-html-data=\"%s\">",
+                               inner_html_data);
+
+                       g_free (inner_html_data);
                }
 
-               g_object_unref (content_stream);
+               g_string_append (buffer, "</div></td></tr>");
+
+               g_free (wrapper_element_id);
        }
 
+       g_clear_object (&content_stream);
+
        g_string_append (buffer, "</table></div>");
 
        g_output_stream_write_all (
@@ -377,47 +331,6 @@ emfe_attachment_format (EMailFormatterExtension *extension,
        return TRUE;
 }
 
-static GtkWidget *
-emfe_attachment_get_widget (EMailFormatterExtension *extension,
-                            EMailPartList *context,
-                            EMailPart *part,
-                            GHashTable *params)
-{
-       EAttachment *attachment;
-       EAttachmentStore *store;
-       EAttachmentView *view;
-       GtkWidget *widget;
-       const gchar *part_id;
-
-       g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), NULL);
-
-       attachment = e_mail_part_attachment_ref_attachment (
-               E_MAIL_PART_ATTACHMENT (part));
-
-       part_id = e_mail_part_get_id (part);
-
-       store = find_attachment_store (context, part);
-       widget = e_attachment_button_new ();
-       g_object_set_data_full (
-               G_OBJECT (widget),
-               "uri", g_strdup (part_id),
-               (GDestroyNotify) g_free);
-       e_attachment_button_set_attachment (
-               E_ATTACHMENT_BUTTON (widget), attachment);
-
-       view = g_object_get_data (G_OBJECT (store), "attachment-bar");
-       if (view != NULL)
-               e_attachment_button_set_view (
-                       E_ATTACHMENT_BUTTON (widget), view);
-
-       gtk_widget_set_can_focus (widget, TRUE);
-       gtk_widget_show (widget);
-
-       g_object_unref (attachment);
-
-       return widget;
-}
-
 static void
 e_mail_formatter_attachment_class_init (EMailFormatterExtensionClass *class)
 {
@@ -426,7 +339,6 @@ e_mail_formatter_attachment_class_init (EMailFormatterExtensionClass *class)
        class->mime_types = formatter_mime_types;
        class->priority = G_PRIORITY_LOW;
        class->format = emfe_attachment_format;
-       class->get_widget = emfe_attachment_get_widget;
 }
 
 static void
diff --git a/em-format/e-mail-formatter-audio.c b/em-format/e-mail-formatter-audio.c
index cf980f8..2837000 100644
--- a/em-format/e-mail-formatter-audio.c
+++ b/em-format/e-mail-formatter-audio.c
@@ -40,7 +40,7 @@ G_DEFINE_TYPE (
        E_TYPE_MAIL_FORMATTER_EXTENSION)
 
 static const gchar *formatter_mime_types[] = {
-       "application/vnd.evolution.widget.audio",
+       "application/vnd.evolution.audio",
        "audio/ac3",
        "audio/x-ac3",
        "audio/basic",
diff --git a/em-format/e-mail-formatter-extension.c b/em-format/e-mail-formatter-extension.c
index 55b481b..3a2dd52 100644
--- a/em-format/e-mail-formatter-extension.c
+++ b/em-format/e-mail-formatter-extension.c
@@ -78,64 +78,3 @@ e_mail_formatter_extension_format (EMailFormatterExtension *extension,
        return class->format (
                extension, formatter, context, part, stream, cancellable);
 }
-
-/**
- * e_mail_formatter_extension_has_widget:
- * @extension: an #EMailFormatterExtension
- *
- * Returns whether the extension can provide a GtkWidget.
- *
- * Returns: Returns %TRUE when @extension reimplements get_widget(), %FALSE
- * otherwise.
- */
-gboolean
-e_mail_formatter_extension_has_widget (EMailFormatterExtension *extension)
-{
-       EMailFormatterExtensionClass *class;
-
-       g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE);
-
-       class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
-
-       return (class->get_widget != NULL);
-}
-
-/**
- * e_mail_formatter_extension_get_widget:
- * @extension: an #EMailFormatterExtension
- * @part: an #EMailPart
- * @params: a #GHashTable
- *
- * A virtual function reimplemented in some mail formatter extensions. The
- * function should construct a #GtkWidget for given @part. The @params hash
- * table can contain additional parameters listed in the &lt;object&gt; HTML
- * element that has requested the widget.
- *
- * When @bind_dom_func is not %NULL, the callee will set a callback function
- * which should be called when the webpage is completely rendered to setup
- * bindings between DOM events and the widget.
- *
- * Returns: Returns a #GtkWidget or %NULL, when error occurs or given
- * @extension does not reimplement this method.
- */
-GtkWidget *
-e_mail_formatter_extension_get_widget (EMailFormatterExtension *extension,
-                                       EMailPartList *context,
-                                       EMailPart *part,
-                                       GHashTable *params)
-{
-       EMailFormatterExtensionClass *class;
-       GtkWidget *widget = NULL;
-
-       g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL);
-       g_return_val_if_fail (part != NULL, NULL);
-       g_return_val_if_fail (params != NULL, NULL);
-
-       class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
-
-       if (class->get_widget != NULL)
-               widget = class->get_widget (extension, context, part, params);
-
-       return widget;
-}
-
diff --git a/em-format/e-mail-formatter-extension.h b/em-format/e-mail-formatter-extension.h
index adfe98f..8e46deb 100644
--- a/em-format/e-mail-formatter-extension.h
+++ b/em-format/e-mail-formatter-extension.h
@@ -83,10 +83,6 @@ struct _EMailFormatterExtensionClass {
                                         EMailPart *part,
                                         GOutputStream *stream,
                                         GCancellable *cancellable);
-       GtkWidget *     (*get_widget)   (EMailFormatterExtension *extension,
-                                        EMailPartList *context,
-                                        EMailPart *part,
-                                        GHashTable *params);
 };
 
 GType          e_mail_formatter_extension_get_type
@@ -98,13 +94,6 @@ gboolean     e_mail_formatter_extension_format
                                                 EMailPart *part,
                                                 GOutputStream *stream,
                                                 GCancellable *cancellable);
-gboolean       e_mail_formatter_extension_has_widget
-                                               (EMailFormatterExtension *extension);
-GtkWidget *    e_mail_formatter_extension_get_widget
-                                               (EMailFormatterExtension *extension,
-                                                EMailPartList *context,
-                                                EMailPart *part,
-                                                GHashTable *params);
 
 G_END_DECLS
 
diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c
index abbc93c..559872f 100644
--- a/em-format/e-mail-formatter.c
+++ b/em-format/e-mail-formatter.c
@@ -63,7 +63,6 @@ struct _AsyncContext {
 
 /* internal formatter extensions */
 GType e_mail_formatter_attachment_get_type (void);
-GType e_mail_formatter_attachment_bar_get_type (void);
 GType e_mail_formatter_audio_get_type (void);
 GType e_mail_formatter_error_get_type (void);
 GType e_mail_formatter_headers_get_type (void);
@@ -96,6 +95,7 @@ enum {
 
 enum {
        NEED_REDRAW,
+       CLAIM_ATTACHMENT,
        LAST_SIGNAL
 };
 
@@ -560,7 +560,6 @@ e_mail_formatter_base_init (EMailFormatterClass *class)
 
        /* Register internal extensions. */
        g_type_ensure (e_mail_formatter_attachment_get_type ());
-       g_type_ensure (e_mail_formatter_attachment_bar_get_type ());
        g_type_ensure (e_mail_formatter_audio_get_type ());
        g_type_ensure (e_mail_formatter_error_get_type ());
        g_type_ensure (e_mail_formatter_headers_get_type ());
@@ -773,6 +772,14 @@ e_mail_formatter_class_init (EMailFormatterClass *class)
                        G_PARAM_READWRITE |
                        G_PARAM_STATIC_STRINGS));
 
+       signals[CLAIM_ATTACHMENT] = g_signal_new (
+               "claim-attachment",
+               E_TYPE_MAIL_FORMATTER,
+               G_SIGNAL_RUN_FIRST,
+               G_STRUCT_OFFSET (EMailFormatterClass, claim_attachment),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, E_TYPE_ATTACHMENT);
+
        signals[NEED_REDRAW] = g_signal_new (
                "need-redraw",
                E_TYPE_MAIL_FORMATTER,
@@ -837,6 +844,16 @@ e_mail_formatter_get_type (void)
 }
 
 void
+e_mail_formatter_claim_attachment (EMailFormatter *formatter,
+                                  EAttachment *attachment)
+{
+       g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+       g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+       g_signal_emit (formatter, signals[CLAIM_ATTACHMENT], 0, attachment);
+}
+
+void
 e_mail_formatter_format_sync (EMailFormatter *formatter,
                               EMailPartList *part_list,
                               GOutputStream *stream,
diff --git a/em-format/e-mail-formatter.h b/em-format/e-mail-formatter.h
index a05755c..777e31a 100644
--- a/em-format/e-mail-formatter.h
+++ b/em-format/e-mail-formatter.h
@@ -85,13 +85,17 @@ struct _EMailFormatterClass {
 
        /* Signals */
        void            (*need_redraw)          (EMailFormatter *formatter);
+       void            (*claim_attachment)     (EMailFormatter *formatter,
+                                                EAttachment *attachment);
 };
 
 GType          e_mail_formatter_get_type       (void);
 
 EMailFormatter *
                e_mail_formatter_new            (void);
-
+void           e_mail_formatter_claim_attachment
+                                               (EMailFormatter *formatter,
+                                                EAttachment *attachment);
 void           e_mail_formatter_format_sync    (EMailFormatter *formatter,
                                                 EMailPartList *part_list,
                                                 GOutputStream *stream,
diff --git a/em-format/e-mail-parser-message.c b/em-format/e-mail-parser-message.c
index 282cef4..0a3b77f 100644
--- a/em-format/e-mail-parser-message.c
+++ b/em-format/e-mail-parser-message.c
@@ -63,12 +63,6 @@ empe_message_parse (EMailParserExtension *extension,
                "application/vnd.evolution.headers",
                cancellable, out_mail_parts);
 
-       /* Attachment Bar */
-       e_mail_parser_parse_part_as (
-               parser, part, part_id,
-               "application/vnd.evolution.widget.attachment-bar",
-               cancellable, out_mail_parts);
-
        ct = camel_mime_part_get_content_type (part);
        mime_type = camel_content_type_simple (ct);
 
diff --git a/em-format/e-mail-parser.c b/em-format/e-mail-parser.c
index c78cb70..c45291a 100644
--- a/em-format/e-mail-parser.c
+++ b/em-format/e-mail-parser.c
@@ -53,7 +53,6 @@ enum {
 
 /* internal parser extensions */
 GType e_mail_parser_application_mbox_get_type (void);
-GType e_mail_parser_attachment_bar_get_type (void);
 GType e_mail_parser_audio_get_type (void);
 GType e_mail_parser_headers_get_type (void);
 GType e_mail_parser_message_get_type (void);
@@ -221,7 +220,6 @@ e_mail_parser_base_init (EMailParserClass *class)
 
        /* Register internal extensions. */
        g_type_ensure (e_mail_parser_application_mbox_get_type ());
-       g_type_ensure (e_mail_parser_attachment_bar_get_type ());
        g_type_ensure (e_mail_parser_audio_get_type ());
        g_type_ensure (e_mail_parser_headers_get_type ());
        g_type_ensure (e_mail_parser_message_get_type ());
diff --git a/em-format/e-mail-part-attachment.h b/em-format/e-mail-part-attachment.h
index bdf859c..0bfeb7e 100644
--- a/em-format/e-mail-part-attachment.h
+++ b/em-format/e-mail-part-attachment.h
@@ -52,7 +52,7 @@ struct _EMailPartAttachment {
        EMailPart parent;
        EMailPartAttachmentPrivate *priv;
 
-       gchar *attachment_view_part_id;
+       gchar *attachment_view_part_id; /* FIXME WK2: maybe drop this property */
 
        gboolean shown;
        const gchar *snoop_mime_type;
diff --git a/em-format/e-mail-part-utils.c b/em-format/e-mail-part-utils.c
index afc28f4..6fef915 100644
--- a/em-format/e-mail-part-utils.c
+++ b/em-format/e-mail-part-utils.c
@@ -485,6 +485,11 @@ e_mail_part_build_uri (CamelFolder *folder,
                                g_free (escaped);
                                break;
                        }
+                       case G_TYPE_POINTER: {
+                               gpointer val = va_arg (ap, gpointer);
+                               tmp2 = g_strdup_printf ("%s%c%s=%p", tmp, separator, name, val);
+                               break;
+                       }
                        default:
                                g_warning ("Invalid param type %s", g_type_name (type));
                                va_end (ap);
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index b733caf..6bd0d09 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -604,6 +604,7 @@ mail_browser_constructed (GObject *object)
        EShellBackend *shell_backend;
        EShell *shell;
        EFocusTracker *focus_tracker;
+       EAttachmentStore *attachment_store;
        GtkAccelGroup *accel_group;
        GtkActionGroup *action_group;
        GtkAction *action;
@@ -752,6 +753,19 @@ mail_browser_constructed (GObject *object)
                browser->priv->preview_pane,
                TRUE, TRUE, 0);
 
+       attachment_store = e_mail_display_get_attachment_store (E_MAIL_DISPLAY (display));
+       widget = e_attachment_bar_new (attachment_store);
+       e_mail_display_set_attachment_view (E_MAIL_DISPLAY (display), E_ATTACHMENT_VIEW (widget));
+       gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+       gtk_widget_show (widget);
+
+       e_binding_bind_property_full (
+               attachment_store, "num-attachments",
+               widget, "visible",
+               G_BINDING_SYNC_CREATE,
+               e_attachment_store_transform_num_attachments_to_visible_boolean,
+               NULL, NULL, NULL);
+
        id = "org.gnome.evolution.mail.browser";
        e_plugin_ui_register_manager (ui_manager, id, object);
        e_plugin_ui_enable_manager (ui_manager, id);
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 24a080e..5bea493 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -52,6 +52,8 @@
        ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
 
 struct _EMailDisplayPrivate {
+       EAttachmentStore *attachment_store;
+       GWeakRef *attachment_view; /* EAttachmentView * */
        EMailPartList *part_list;
        EMailFormatterMode mode;
        EMailFormatter *formatter;
@@ -62,8 +64,6 @@ struct _EMailDisplayPrivate {
 
        GSettings *settings;
 
-       GHashTable *widgets;
-
        guint scheduled_reload;
 
        GHashTable *old_settings;
@@ -73,10 +73,14 @@ struct _EMailDisplayPrivate {
        GHashTable *skipped_remote_content_sites;
 
        guint web_extension_headers_collapsed_signal_id;
+
+       GtkAllocation attachment_popup_position;
 };
 
 enum {
        PROP_0,
+       PROP_ATTACHMENT_STORE,
+       PROP_ATTACHMENT_VIEW,
        PROP_FORMATTER,
        PROP_HEADERS_COLLAPSABLE,
        PROP_HEADERS_COLLAPSED,
@@ -278,30 +282,6 @@ mail_display_update_formatter_colors (EMailDisplay *display)
                e_mail_formatter_update_style (formatter, state_flags);
 }
 
-#if 0
-static void
-mail_display_plugin_widget_disconnect_children (GtkWidget *widget,
-                                                gpointer mail_display)
-{
-       g_signal_handlers_disconnect_by_data (widget, mail_display);
-}
-
-static void
-mail_display_plugin_widget_disconnect (gpointer widget_uri,
-                                       gpointer widget,
-                                       gpointer mail_display)
-{
-       if (E_IS_ATTACHMENT_BAR (widget))
-               g_signal_handlers_disconnect_by_data (widget, mail_display);
-       else if (E_IS_ATTACHMENT_BUTTON (widget))
-               g_signal_handlers_disconnect_by_data (widget, mail_display);
-       else if (GTK_IS_CONTAINER (widget))
-               gtk_container_foreach (
-                       widget,
-                       mail_display_plugin_widget_disconnect_children,
-                       mail_display);
-}
-#endif
 static gboolean
 mail_display_process_mailto (EWebView *web_view,
                              const gchar *mailto_uri,
@@ -390,542 +370,8 @@ decide_policy_cb (WebKitWebView *web_view,
        /* Let WebKit handle it. */
        return FALSE;
 }
-#if 0 /* FIXME WK2 */
-static WebKitDOMElement *
-find_element_by_id (WebKitDOMDocument *document,
-                    const gchar *id)
-{
-       WebKitDOMNodeList *frames;
-       WebKitDOMElement *element = NULL;
-       gulong ii, length;
-
-       if (!WEBKIT_DOM_IS_DOCUMENT (document))
-               return NULL;
-
-       /* Try to look up the element in this DOM document */
-       element = webkit_dom_document_get_element_by_id (document, id);
-       if (element != NULL)
-               return element;
-
-       /* If the element is not here then recursively scan all frames */
-       frames = webkit_dom_document_get_elements_by_tag_name (
-               document, "iframe");
-       length = webkit_dom_node_list_get_length (frames);
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMHTMLIFrameElement *iframe;
-               WebKitDOMDocument *frame_doc;
-               WebKitDOMElement *element;
-
-               iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
-                       webkit_dom_node_list_item (frames, ii));
-
-               frame_doc = webkit_dom_html_iframe_element_get_content_document (iframe);
-
-               element = find_element_by_id (frame_doc, id);
-
-               if (element != NULL)
-                       goto out;
-       }
- out:
-       g_object_unref (frames);
-
-       return element;
-}
-
-static void
-mail_display_plugin_widget_resize (GtkWidget *widget,
-                                   gpointer dummy,
-                                   EMailDisplay *display)
-{
-       WebKitDOMElement *parent_element;
-       gchar *dim;
-       gint height, width;
-       gfloat scale;
-
-       parent_element = g_object_get_data (
-               G_OBJECT (widget), "parent_element");
-
-       if (!WEBKIT_DOM_IS_ELEMENT (parent_element)) {
-               d (
-                       printf ("%s: %s does not have (valid) parent element!\n",
-                       G_STRFUNC, (gchar *) g_object_get_data (G_OBJECT (widget), "uri")));
-               return;
-       }
-
-       scale = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (display));
-       width = gtk_widget_get_allocated_width (widget);
-       gtk_widget_get_preferred_height_for_width (widget, width, &height, NULL);
-
-       /* When zooming WebKit does not change dimensions of the elements,
-        * but only scales them on the canvas.  GtkWidget can't be scaled
-        * though so we need to cope with the dimension changes to keep the
-        * the widgets the correct size.  Due to inaccuracy in rounding
-        * (float -> int) it still acts a bit funny, but at least it does
-        * not cause widgets in WebKit to go crazy when zooming. */
-       height = height * (1 / scale);
-
-       /* Int -> Str */
-       dim = g_strdup_printf ("%d", height);
-
-       /* Set height of the containment <object> to match height of the
-        * GtkWidget it contains */
-       webkit_dom_html_object_element_set_height (
-               WEBKIT_DOM_HTML_OBJECT_ELEMENT (parent_element), dim);
-       g_free (dim);
-}
-
-static void
-plugin_widget_set_parent_element (GtkWidget *widget,
-                                  EMailDisplay *display)
-{
-       const gchar *uri;
-       WebKitDOMDocument *document;
-       WebKitDOMElement *element;
-
-       uri = g_object_get_data (G_OBJECT (widget), "uri");
-       if (uri == NULL || *uri == '\0')
-               return;
-
-       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
-       element = find_element_by_id (document, uri);
-
-       if (!WEBKIT_DOM_IS_ELEMENT (element)) {
-               g_warning ("Failed to find parent <object> for '%s' - no ID set?", uri);
-               return;
-       }
-
-       /* Assign the WebKitDOMElement to "parent_element" data of the
-        * GtkWidget and the GtkWidget to "widget" data of the DOM Element. */
-       g_object_set_data (G_OBJECT (widget), "parent_element", element);
-       g_object_set_data (G_OBJECT (element), "widget", widget);
-
-       e_binding_bind_property (
-               element, "hidden",
-               widget, "visible",
-               G_BINDING_SYNC_CREATE |
-               G_BINDING_INVERT_BOOLEAN);
-}
-
-static void
-attachment_button_expanded (GObject *object,
-                            GParamSpec *pspec,
-                            gpointer user_data)
-{
-       EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
-       EMailDisplay *display = user_data;
-       WebKitDOMDocument *document;
-       WebKitDOMElement *element, *iframe;
-       WebKitDOMCSSStyleDeclaration *css;
-       const gchar *attachment_part_id;
-       gchar *element_id;
-       gboolean expanded;
-
-       d (
-               printf ("Attachment button %s has been %s!\n",
-               (gchar *) g_object_get_data (object, "uri"),
-               (e_attachment_button_get_expanded (button) ? "expanded" : "collapsed")));
-
-       expanded =
-               e_attachment_button_get_expanded (button) &&
-               gtk_widget_get_visible (GTK_WIDGET (button));
-
-       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
-       attachment_part_id = g_object_get_data (object, "attachment_id");
-
-       element_id = g_strconcat (attachment_part_id, ".wrapper", NULL);
-       element = find_element_by_id (document, element_id);
-       g_free (element_id);
-
-       if (!WEBKIT_DOM_IS_ELEMENT (element)) {
-               d (
-                       printf ("%s: Content <div> of attachment %s does not exist!!\n",
-                       G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
-               return;
-       }
-
-       if (WEBKIT_DOM_IS_HTML_ELEMENT (element) && expanded &&
-           webkit_dom_element_get_child_element_count (element) == 0) {
-               gchar *inner_html_data;
-
-               inner_html_data = webkit_dom_element_get_attribute (element, "inner-html-data");
-               if (inner_html_data && *inner_html_data) {
-                       WebKitDOMHTMLElement *html_element;
-
-                       html_element = WEBKIT_DOM_HTML_ELEMENT (element);
-                       webkit_dom_html_element_set_inner_html (html_element, inner_html_data, NULL);
-
-                       webkit_dom_element_remove_attribute (element, "inner-html-data");
-               }
-
-               g_free (inner_html_data);
-       }
-
-       /* Hide/Show all the GtkWidgets inside an attachment, otherwise they could
-        * be visible even if the wrapper is hidden. */
-       if ((iframe = webkit_dom_element_query_selector (element, "iframe", NULL))) {
-               WebKitDOMDocument *content_document;
-
-               content_document = webkit_dom_html_iframe_element_get_content_document
-                       (WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
-
-               if (content_document) {
-                       gint length, ii;
-                       WebKitDOMNodeList *list;
-
-                       list = webkit_dom_document_get_elements_by_tag_name (content_document, "object");
-                       length = webkit_dom_node_list_get_length (list);
-
-                       for (ii = 0; ii < length; ii++) {
-                               WebKitDOMNode *item;
-
-                               item = webkit_dom_node_list_item (list, ii);
-
-                               css = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (item));
-                               if (expanded)
-                                       g_free (webkit_dom_css_style_declaration_remove_property (css, 
"display", NULL));
-                               else
-                                       webkit_dom_css_style_declaration_set_property (css, "display", 
"none", "", NULL);
-                               g_clear_object (&css);
-                       }
-                       g_object_unref (list);
-               }
-       }
-
-       /* Show or hide the DIV which contains
-        * the attachment (iframe, image...). */
-       css = webkit_dom_element_get_style (element);
-       webkit_dom_css_style_declaration_set_property (
-               css, "display", expanded ? "block" : "none", "", NULL);
-}
 
 static void
-attachment_button_zoom_to_window_cb (GObject *object,
-                                    GParamSpec *pspec,
-                                    gpointer user_data)
-{
-       EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
-       EMailDisplay *display = user_data;
-       WebKitDOMDocument *document;
-       WebKitDOMElement *element, *child;
-       WebKitDOMCSSStyleDeclaration *css;
-       const gchar *attachment_part_id;
-       gchar *element_id;
-       gboolean zoom_to_window;
-
-       d (
-               printf ("Attachment button %s has been set to %s!\n",
-               (gchar *) g_object_get_data (object, "uri"),
-               (e_attachment_botton_get_zoom_to_window (attachment) ? "zoom-to-window" : "zoom to 100%")));
-
-       if (!gtk_widget_get_visible (GTK_WIDGET (button)))
-               return;
-
-       zoom_to_window = e_attachment_button_get_zoom_to_window (button);
-
-       document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
-       attachment_part_id = g_object_get_data (object, "attachment_id");
-
-       element_id = g_strconcat (attachment_part_id, ".wrapper", NULL);
-       element = find_element_by_id (document, element_id);
-       g_free (element_id);
-
-       if (!WEBKIT_DOM_IS_ELEMENT (element)) {
-               d (
-                       printf ("%s: Content <div> of attachment %s does not exist!!\n",
-                       G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
-               return;
-       }
-
-       child = webkit_dom_element_get_first_element_child (element);
-       if (!child || !WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (child)) {
-               d (
-                       printf ("%s: Content <div> of attachment %s does not contain image, but %s\n",
-                       G_STRFUNC, (gchar *) g_object_get_data (object, "uri"),
-                       child ? G_OBJECT_TYPE_NAME (child) : "[null]"));
-               g_clear_object (&child);
-               return;
-       }
-
-       css = webkit_dom_element_get_style (child);
-       if (zoom_to_window) {
-               webkit_dom_css_style_declaration_set_property (css, "max-width", "100%", "", NULL);
-       } else {
-               g_free (webkit_dom_css_style_declaration_remove_property (css, "max-width", NULL));
-       }
-       g_object_unref (css);
-       g_clear_object (&child);
-}
-
-static void
-mail_display_attachment_count_changed (EAttachmentStore *store,
-                                       GParamSpec *pspec,
-                                       GtkWidget *box)
-{
-       WebKitDOMHTMLElement *element;
-       GList *children;
-
-       children = gtk_container_get_children (GTK_CONTAINER (box));
-       g_return_if_fail (children && children->data);
-
-       element = g_object_get_data (children->data, "parent_element");
-       g_list_free (children);
-
-       g_return_if_fail (WEBKIT_DOM_IS_HTML_ELEMENT (element));
-
-       if (e_attachment_store_get_num_attachments (store) == 0) {
-               gtk_widget_hide (box);
-               webkit_dom_html_element_set_hidden (element, TRUE);
-       } else {
-               gtk_widget_show (box);
-               webkit_dom_html_element_set_hidden (element, FALSE);
-       }
-}
-
-typedef struct _NumAttachmentsData {
-       EAttachmentStore *store;
-       gulong handler_id;
-} NumAttachmentsData;
-
-static void
-attachment_bar_box_gone_cb (gpointer data,
-                           GObject *gone_box)
-{
-       NumAttachmentsData *nad = data;
-
-       if (nad) {
-               g_signal_handler_disconnect (nad->store, nad->handler_id);
-               g_object_unref (nad->store);
-               g_free (nad);
-       }
-}
-
-static GtkWidget *
-mail_display_plugin_widget_requested (WebKitWebView *web_view,
-                                      gchar *mime_type,
-                                      gchar *uri,
-                                      GHashTable *param,
-                                      gpointer user_data)
-{
-       EMailDisplay *display;
-       EMailExtensionRegistry *reg;
-       EMailFormatterExtension *extension;
-       GQueue *extensions;
-       GList *head, *link;
-       EMailPart *part = NULL;
-       GtkWidget *widget = NULL;
-       GWeakRef *weakref;
-       gchar *part_id, *type, *object_uri;
-
-       part_id = g_hash_table_lookup (param, "data");
-       if (part_id == NULL || !g_str_has_prefix (uri, "mail://"))
-               return NULL;
-
-       type = g_hash_table_lookup (param, "type");
-       if (type == NULL)
-               return NULL;
-
-       display = E_MAIL_DISPLAY (web_view);
-
-       weakref = g_hash_table_lookup (display->priv->widgets, part_id);
-       if (weakref)
-               widget = g_weak_ref_get (weakref);
-
-       if (widget != NULL) {
-               /* This cannot be the last reference; thread-safety is assured,
-                  because this runs in the main thread only. */
-               g_object_unref (widget);
-               d (printf ("Handeled %s widget request from cache\n", part_id));
-               return widget;
-       }
-
-       /* Find the EMailPart representing the requested widget. */
-       part = e_mail_part_list_ref_part (display->priv->part_list, part_id);
-       if (part == NULL)
-               return NULL;
-
-       reg = e_mail_formatter_get_extension_registry (display->priv->formatter);
-       extensions = e_mail_extension_registry_get_for_mime_type (reg, type);
-       if (extensions == NULL)
-               goto exit;
-
-       extension = NULL;
-       head = g_queue_peek_head_link (extensions);
-       for (link = head; link != NULL; link = g_list_next (link)) {
-               extension = link->data;
-
-               if (extension == NULL)
-                       continue;
-
-               if (e_mail_formatter_extension_has_widget (extension))
-                       break;
-       }
-
-       if (extension == NULL)
-               goto exit;
-
-       /* Get the widget from formatter */
-       widget = e_mail_formatter_extension_get_widget (
-               extension, display->priv->part_list, part, param);
-       d (
-               printf ("Created widget %s (%p) for part %s\n",
-                       G_OBJECT_TYPE_NAME (widget), widget, part_id));
-
-       /* Should not happen! WebKit will display an ugly 'Plug-in not
-        * available' placeholder instead of hiding the <object> element. */
-       if (widget == NULL)
-               goto exit;
-
-       /* Attachment button has URI different then the actual PURI because
-        * that URI identifies the attachment itself */
-       if (E_IS_ATTACHMENT_BUTTON (widget)) {
-               EMailPartAttachment *empa = (EMailPartAttachment *) part;
-               EAttachment *attachment;
-               gchar *attachment_part_id;
-
-               if (empa->attachment_view_part_id)
-                       attachment_part_id = empa->attachment_view_part_id;
-               else
-                       attachment_part_id = part_id;
-
-               object_uri = g_strconcat (
-                       attachment_part_id, ".attachment_button", NULL);
-               g_object_set_data_full (
-                       G_OBJECT (widget), "attachment_id",
-                       g_strdup (attachment_part_id),
-                       (GDestroyNotify) g_free);
-
-               attachment = e_mail_part_attachment_ref_attachment (empa);
-               if (attachment && e_attachment_is_mail_note (attachment)) {
-                       CamelFolder *folder;
-                       const gchar *message_uid;
-
-                       folder = e_mail_part_list_get_folder (display->priv->part_list);
-                       message_uid = e_mail_part_list_get_message_uid (display->priv->part_list);
-
-                       if (folder && message_uid) {
-                               CamelMessageInfo *info;
-
-                               info = camel_folder_get_message_info (folder, message_uid);
-                               if (info) {
-                                       if (!camel_message_info_user_flag (info, E_MAIL_NOTES_USER_FLAG))
-                                               camel_message_info_set_user_flag (info, 
E_MAIL_NOTES_USER_FLAG, TRUE);
-                                       camel_message_info_unref (info);
-                               }
-                       }
-               }
-
-               g_clear_object (&attachment);
-       } else {
-               object_uri = g_strdup (part_id);
-       }
-
-       /* Store the uri as data of the widget */
-       g_object_set_data_full (
-               G_OBJECT (widget), "uri",
-               object_uri, (GDestroyNotify) g_free);
-
-       /* Set pointer to the <object> element as GObject data
-        * "parent_element" and set pointer to the widget as GObject
-        * data "widget" to the <object> element. */
-       plugin_widget_set_parent_element (widget, display);
-
-       /* Resizing a GtkWidget requires changing size of parent
-        * <object> HTML element in DOM. */
-       g_signal_connect (
-               widget, "size-allocate",
-               G_CALLBACK (mail_display_plugin_widget_resize), display);
-
-       if (E_IS_ATTACHMENT_BAR (widget)) {
-               GtkWidget *box = NULL;
-               EAttachmentStore *store;
-               NumAttachmentsData *nad;
-
-               /* Only when packed in box (grid does not work),
-                * EAttachmentBar reports correct height */
-               box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-               gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0);
-
-               /* When EAttachmentBar is expanded/collapsed it does not
-                * emit size-allocate signal despite it changes it's height. */
-               g_signal_connect (
-                       widget, "notify::expanded",
-                       G_CALLBACK (mail_display_plugin_widget_resize),
-                       display);
-               g_signal_connect (
-                       widget, "notify::active-view",
-                       G_CALLBACK (mail_display_plugin_widget_resize),
-                       display);
-
-               /* Always hide an attachment bar without attachments */
-               store = e_attachment_bar_get_store (E_ATTACHMENT_BAR (widget));
-
-               nad = g_new0 (NumAttachmentsData, 1);
-               nad->store = g_object_ref (store);
-               nad->handler_id = g_signal_connect (
-                       store, "notify::num-attachments",
-                       G_CALLBACK (mail_display_attachment_count_changed),
-                       box);
-
-               g_object_weak_ref (G_OBJECT (box), attachment_bar_box_gone_cb, nad);
-
-               gtk_widget_show (widget);
-               gtk_widget_show (box);
-
-               /* Initial sync */
-               mail_display_attachment_count_changed (store, NULL, box);
-
-               widget = box;
-
-       } else if (E_IS_ATTACHMENT_BUTTON (widget)) {
-
-               /* Bind visibility of DOM element containing related
-                * attachment with 'expanded' property of this
-                * attachment button. */
-               EMailPartAttachment *empa = (EMailPartAttachment *) part;
-
-               e_attachment_button_set_expandable (E_ATTACHMENT_BUTTON (widget),
-                       e_mail_part_attachment_get_expandable (empa));
-
-               if (e_mail_part_attachment_get_expandable (empa)) {
-                       /* Show/hide the attachment when the EAttachmentButton
-                        * is expanded/collapsed or shown/hidden. */
-                       g_signal_connect (
-                               widget, "notify::expanded",
-                               G_CALLBACK (attachment_button_expanded),
-                               display);
-                       g_signal_connect (
-                               widget, "notify::visible",
-                               G_CALLBACK (attachment_button_expanded),
-                               display);
-                       g_signal_connect (
-                               widget, "notify::zoom-to-window",
-                               G_CALLBACK (attachment_button_zoom_to_window_cb),
-                               display);
-
-                       if (e_mail_part_should_show_inline (part)) {
-                               e_attachment_button_set_expanded (
-                                       E_ATTACHMENT_BUTTON (widget), TRUE);
-                       } else {
-                               e_attachment_button_set_expanded (
-                                       E_ATTACHMENT_BUTTON (widget), FALSE);
-                               attachment_button_expanded (
-                                       G_OBJECT (widget), NULL, display);
-                       }
-               }
-       }
-
-       g_hash_table_insert (
-               display->priv->widgets,
-               g_strdup (object_uri), e_weak_ref_new (widget));
-
-exit:
-       if (part != NULL)
-               g_object_unref (part);
-
-       return widget;
-}
-#endif
-static void
 add_color_css_rule_for_web_view (EWebView *view,
                                  const gchar *color_name,
                                  const gchar *color_value)
@@ -1061,19 +507,11 @@ headers_collapsed_signal_cb (GDBusConnection *connection,
 }
 
 static void
-setup_dom_bindings (WebKitWebView *web_view,
-                    WebKitLoadEvent load_event,
-                    gpointer user_data)
+setup_dom_bindings (EMailDisplay *display)
 {
        GDBusProxy *web_extension;
-       EMailDisplay *display;
-
-       if (load_event != WEBKIT_LOAD_FINISHED)
-               return;
 
-       display = E_MAIL_DISPLAY (web_view);
-
-       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
+       web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
 
        if (web_extension) {
                if (display->priv->web_extension_headers_collapsed_signal_id == 0) {
@@ -1096,7 +534,7 @@ setup_dom_bindings (WebKitWebView *web_view,
                        "EMailDisplayBindDOM",
                        g_variant_new (
                                "(t)",
-                               webkit_web_view_get_page_id (web_view)),
+                               webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (display))),
                        G_DBUS_CALL_FLAGS_NONE,
                        -1,
                        NULL,
@@ -1105,6 +543,281 @@ setup_dom_bindings (WebKitWebView *web_view,
        }
 }
 
+static EAttachment *
+mail_display_ref_attachment_from_element (EMailDisplay *display,
+                                         const gchar *element_value)
+{
+       EAttachment *attachment = NULL;
+       GQueue queue = G_QUEUE_INIT;
+       GList *head, *link;
+
+       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+       g_return_val_if_fail (element_value != NULL, NULL);
+
+       e_mail_part_list_queue_parts (display->priv->part_list, NULL, &queue);
+       head = g_queue_peek_head_link (&queue);
+
+       for (link = head; link != NULL; link = g_list_next (link)) {
+               EMailPart *part = E_MAIL_PART (link->data);
+
+               if (E_IS_MAIL_PART_ATTACHMENT (part)) {
+                       EAttachment *adept;
+                       gboolean can_use;
+                       gchar *tmp;
+
+                       adept = e_mail_part_attachment_ref_attachment (E_MAIL_PART_ATTACHMENT (part));
+
+                       tmp = g_strdup_printf ("%p", adept);
+                       can_use = g_strcmp0 (tmp, element_value) == 0;
+                       g_free (tmp);
+
+                       if (can_use) {
+                               attachment = adept;
+                               break;
+                       }
+
+                       g_clear_object (&adept);
+               }
+       }
+
+       while (!g_queue_is_empty (&queue))
+               g_object_unref (g_queue_pop_head (&queue));
+
+       return attachment;
+}
+
+static void
+mail_display_attachment_expander_clicked_cb (EWebView *web_view,
+                                            const gchar *element_class,
+                                            const gchar *element_value,
+                                            const GtkAllocation *element_position,
+                                            gpointer user_data)
+{
+       EMailDisplay *display;
+       EAttachmentView *view;
+       EAttachment *attachment;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
+       g_return_if_fail (element_class != NULL);
+       g_return_if_fail (element_value != NULL);
+       g_return_if_fail (element_position != NULL);
+
+       display = E_MAIL_DISPLAY (web_view);
+       view = e_mail_display_ref_attachment_view (display);
+       attachment = mail_display_ref_attachment_from_element (display, element_value);
+
+       if (view && attachment) {
+               /* mail_display_attachment_notify_cb() takes care of the HTML part */
+               e_attachment_set_shown (attachment, !e_attachment_get_shown (attachment));
+       }
+
+       g_clear_object (&attachment);
+       g_clear_object (&view);
+}
+
+static void
+mail_display_attachment_menu_deactivate_cb (GtkMenuShell *menu,
+                                           gpointer user_data)
+{
+       EMailDisplay *display = user_data;
+       EAttachmentView *view;
+       GtkActionGroup *action_group;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       view = e_mail_display_ref_attachment_view (display);
+       action_group = e_attachment_view_get_action_group (view, "inline");
+
+       gtk_action_group_set_visible (action_group, FALSE);
+
+       g_signal_handlers_disconnect_by_func (menu,
+               G_CALLBACK (mail_display_attachment_menu_deactivate_cb), display);
+}
+
+static void
+mail_display_attachment_menu_position_cb (GtkMenu *menu,
+                                         gint *x,
+                                         gint *y,
+                                         gboolean *push_in,
+                                         gpointer user_data)
+{
+       GtkRequisition menu_requisition;
+       GtkTextDirection direction;
+       GtkAllocation allocation;
+       GdkRectangle monitor;
+       GdkScreen *screen;
+       GdkWindow *window;
+       GtkWidget *widget;
+       EMailDisplay *display = user_data;
+       gint monitor_num;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       widget = GTK_WIDGET (display);
+       gtk_widget_get_preferred_size (GTK_WIDGET (menu), &menu_requisition, NULL);
+
+       window = gtk_widget_get_parent_window (widget);
+       screen = gtk_widget_get_screen (GTK_WIDGET (menu));
+       monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+       if (monitor_num < 0)
+               monitor_num = 0;
+       gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+       allocation = display->priv->attachment_popup_position;
+
+       gdk_window_get_origin (window, x, y);
+       *x += allocation.x;
+       *y += allocation.y + allocation.height;
+
+       direction = gtk_widget_get_direction (widget);
+       if (direction == GTK_TEXT_DIR_LTR)
+               *x += MAX (allocation.width - menu_requisition.width, 0);
+       else if (menu_requisition.width > allocation.width)
+               *x -= menu_requisition.width - allocation.width;
+
+       *push_in = FALSE;
+}
+
+static void
+mail_display_attachment_select_path (EAttachmentView *view,
+                                    EAttachment *attachment)
+{
+       GtkTreeRowReference *reference;
+       GtkTreePath *path;
+
+       g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+       g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+       reference = e_attachment_get_reference (attachment);
+       g_return_if_fail (gtk_tree_row_reference_valid (reference));
+
+       path = gtk_tree_row_reference_get_path (reference);
+
+       e_attachment_view_unselect_all (view);
+       e_attachment_view_select_path (view, path);
+
+       gtk_tree_path_free (path);
+}
+
+static void
+mail_display_attachment_menu_clicked_cb (EWebView *web_view,
+                                        const gchar *element_class,
+                                        const gchar *element_value,
+                                        const GtkAllocation *element_position,
+                                        gpointer user_data)
+{
+       EMailDisplay *display;
+       EAttachmentView *view;
+       EAttachment *attachment;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
+       g_return_if_fail (element_class != NULL);
+       g_return_if_fail (element_value != NULL);
+       g_return_if_fail (element_position != NULL);
+
+       display = E_MAIL_DISPLAY (web_view);
+       view = e_mail_display_ref_attachment_view (display);
+       attachment = mail_display_ref_attachment_from_element (display, element_value);
+
+       if (view && attachment) {
+               GtkActionGroup *action_group;
+               GtkWidget *popup_menu;
+
+               popup_menu = e_attachment_view_get_popup_menu (view);
+
+               g_signal_connect (
+                       popup_menu, "deactivate",
+                       G_CALLBACK (mail_display_attachment_menu_deactivate_cb), display);
+
+               action_group = e_attachment_view_get_action_group (view, "inline");
+
+               mail_display_attachment_select_path (view, attachment);
+               display->priv->attachment_popup_position = *element_position;
+
+               e_attachment_view_show_popup_menu (view, NULL,
+                       mail_display_attachment_menu_position_cb, display);
+
+               gtk_action_group_set_visible (action_group, TRUE);
+       }
+
+       g_clear_object (&attachment);
+       g_clear_object (&view);
+}
+
+static void
+mail_display_attachment_notify_cb (GObject *attachment,
+                                  GParamSpec *param,
+                                  gpointer user_data)
+{
+       EMailDisplay *display = user_data;
+       gchar *element_id = NULL;
+
+       g_return_if_fail (E_IS_ATTACHMENT (attachment));
+       g_return_if_fail (param != NULL);
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       if (g_str_equal (param->name, "shown")) {
+               gboolean shown;
+               gchar *uri;
+
+               shown = e_attachment_get_shown (E_ATTACHMENT (attachment));
+
+               element_id = g_strdup_printf ("attachment-wrapper-%p", attachment);
+               e_web_view_set_element_hidden (E_WEB_VIEW (display), element_id, !shown);
+
+               g_free (element_id);
+               element_id = g_strdup_printf ("attachment-expander-img-%p", attachment);
+               uri = g_strdup_printf ("gtk-stock://%s?size=%d", shown ? "go-down" : "go-next", 
GTK_ICON_SIZE_BUTTON);
+
+               e_web_view_set_element_attribute (E_WEB_VIEW (display), element_id, NULL, "src", uri);
+
+               g_free (uri);
+       } else if (g_str_equal (param->name, "zoom-to-window")) {
+               const gchar *value;
+
+               if (e_attachment_get_zoom_to_window (E_ATTACHMENT (attachment)))
+                       value = "100%";
+               else
+                       value = NULL;
+
+               element_id = g_strdup_printf ("attachment-wrapper-%p::child", attachment);
+
+               e_web_view_set_element_style_property (E_WEB_VIEW (display), element_id, "max-width", value, 
"");
+       }
+
+       g_free (element_id);
+}
+
+static void
+mail_display_attachment_added_cb (EAttachmentStore *store,
+                                 EAttachment *attachment,
+                                 gpointer user_data)
+{
+       EMailDisplay *display = user_data;
+
+       g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+       g_return_if_fail (E_IS_ATTACHMENT (attachment));
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       g_signal_connect (attachment, "notify",
+               G_CALLBACK (mail_display_attachment_notify_cb), display);
+}
+
+static void
+mail_display_attachment_removed_cb (EAttachmentStore *store,
+                                   EAttachment *attachment,
+                                   gpointer user_data)
+{
+       EMailDisplay *display = user_data;
+
+       g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+       g_return_if_fail (E_IS_ATTACHMENT (attachment));
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       g_signal_handlers_disconnect_by_func (attachment,
+               G_CALLBACK (mail_display_attachment_notify_cb), display);
+}
+
 static void
 mail_element_exists_cb (GDBusProxy *web_extension,
                         GAsyncResult *result,
@@ -1131,25 +844,15 @@ mail_element_exists_cb (GDBusProxy *web_extension,
 }
 
 static void
-mail_parts_bind_dom (WebKitWebView *wk_web_view,
-                     WebKitLoadEvent load_event,
-                     gpointer user_data)
+mail_parts_bind_dom (EMailDisplay *display)
 {
-       EMailDisplay *display;
        EWebView *web_view;
        GQueue queue = G_QUEUE_INIT;
        GList *head, *link;
        GDBusProxy *web_extension;
+       gboolean has_attachment = FALSE;
 
-       display = E_MAIL_DISPLAY (wk_web_view);
-
-       if (load_event == WEBKIT_LOAD_STARTED) {
-               e_mail_display_cleanup_skipped_uris (display);
-               return;
-       }
-
-       if (load_event != WEBKIT_LOAD_FINISHED)
-               return;
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
 
        if (display->priv->part_list == NULL)
                return;
@@ -1171,6 +874,8 @@ mail_parts_bind_dom (WebKitWebView *wk_web_view,
 
                part_id = e_mail_part_get_id (part);
 
+               has_attachment = has_attachment || E_IS_MAIL_PART_ATTACHMENT (part);
+
                e_mail_part_web_view_loaded (part, web_view);
 
                g_dbus_proxy_call (
@@ -1190,29 +895,38 @@ mail_parts_bind_dom (WebKitWebView *wk_web_view,
 
        while (!g_queue_is_empty (&queue))
                g_object_unref (g_queue_pop_head (&queue));
+
+       if (has_attachment) {
+               e_web_view_register_element_clicked (web_view, "attachment-expander",
+                       mail_display_attachment_expander_clicked_cb, NULL);
+               e_web_view_register_element_clicked (web_view, "attachment-menu",
+                       mail_display_attachment_menu_clicked_cb, NULL);
+       }
 }
-#if 0
+
 static void
-mail_display_uri_changed (EMailDisplay *display,
-                          GParamSpec *pspec,
-                          gpointer dummy)
+mail_display_load_changed_cb (WebKitWebView *wk_web_view,
+                             WebKitLoadEvent load_event,
+                             gpointer user_data)
 {
-       d (printf ("EMailDisplay URI changed, recreating widgets hashtable\n"));
+       EMailDisplay *display;
+
+       g_return_if_fail (E_IS_MAIL_DISPLAY (wk_web_view));
+
+       display = E_MAIL_DISPLAY (wk_web_view);
 
-       if (display->priv->widgets != NULL) {
-               g_hash_table_foreach (
-                       display->priv->widgets,
-                       mail_display_plugin_widget_disconnect, display);
-               g_hash_table_destroy (display->priv->widgets);
+       if (load_event == WEBKIT_LOAD_STARTED) {
+               e_mail_display_cleanup_skipped_uris (display);
+               e_attachment_store_remove_all (display->priv->attachment_store);
+               return;
        }
 
-       display->priv->widgets = g_hash_table_new_full (
-               (GHashFunc) g_str_hash,
-               (GEqualFunc) g_str_equal,
-               (GDestroyNotify) g_free,
-               (GDestroyNotify) e_weak_ref_free);
+       if (load_event == WEBKIT_LOAD_FINISHED) {
+               setup_dom_bindings (display);
+               mail_parts_bind_dom (display);
+       }
 }
-#endif
+
 static void
 mail_display_set_property (GObject *object,
                            guint property_id,
@@ -1220,6 +934,12 @@ mail_display_set_property (GObject *object,
                            GParamSpec *pspec)
 {
        switch (property_id) {
+               case PROP_ATTACHMENT_VIEW:
+                       e_mail_display_set_attachment_view (
+                               E_MAIL_DISPLAY (object),
+                               g_value_get_object (value));
+                       return;
+
                case PROP_HEADERS_COLLAPSABLE:
                        e_mail_display_set_headers_collapsable (
                                E_MAIL_DISPLAY (object),
@@ -1261,6 +981,20 @@ mail_display_get_property (GObject *object,
                            GParamSpec *pspec)
 {
        switch (property_id) {
+               case PROP_ATTACHMENT_STORE:
+                       g_value_set_object (
+                               value,
+                               e_mail_display_get_attachment_store (
+                               E_MAIL_DISPLAY (object)));
+                       return;
+
+               case PROP_ATTACHMENT_VIEW:
+                       g_value_take_object (
+                               value,
+                               e_mail_display_ref_attachment_view (
+                               E_MAIL_DISPLAY (object)));
+                       return;
+
                case PROP_FORMATTER:
                        g_value_set_object (
                                value,
@@ -1318,15 +1052,7 @@ mail_display_dispose (GObject *object)
                g_source_remove (priv->scheduled_reload);
                priv->scheduled_reload = 0;
        }
-#if 0
-       if (priv->widgets != NULL) {
-               g_hash_table_foreach (
-                       priv->widgets,
-                       mail_display_plugin_widget_disconnect, object);
-               g_hash_table_destroy (priv->widgets);
-               priv->widgets = NULL;
-       }
-#endif
+
        if (priv->settings != NULL)
                g_signal_handlers_disconnect_matched (
                        priv->settings, G_SIGNAL_MATCH_DATA,
@@ -1340,9 +1066,21 @@ mail_display_dispose (GObject *object)
                priv->web_extension_headers_collapsed_signal_id = 0;
        }
 
+       if (priv->attachment_store) {
+               /* To have called the mail_display_attachment_removed_cb() before it's disconnected */
+               e_attachment_store_remove_all (priv->attachment_store);
+
+               g_signal_handlers_disconnect_by_func (priv->attachment_store,
+                       G_CALLBACK (mail_display_attachment_added_cb), object);
+
+               g_signal_handlers_disconnect_by_func (priv->attachment_store,
+                       G_CALLBACK (mail_display_attachment_removed_cb), object);
+       }
+
        g_clear_object (&priv->part_list);
        g_clear_object (&priv->formatter);
        g_clear_object (&priv->settings);
+       g_clear_object (&priv->attachment_store);
 
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_mail_display_parent_class)->dispose (object);
@@ -1369,6 +1107,7 @@ mail_display_finalize (GObject *object)
        g_clear_object (&priv->remote_content);
        g_mutex_unlock (&priv->remote_content_lock);
        g_mutex_clear (&priv->remote_content_lock);
+       e_weak_ref_free (priv->attachment_view);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_mail_display_parent_class)->finalize (object);
@@ -1803,6 +1542,28 @@ e_mail_display_class_init (EMailDisplayClass *class)
 
        g_object_class_install_property (
                object_class,
+               PROP_ATTACHMENT_STORE,
+               g_param_spec_object (
+                       "attachment-store",
+                       "Attachment Store",
+                       NULL,
+                       E_TYPE_ATTACHMENT_STORE,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ATTACHMENT_VIEW,
+               g_param_spec_object (
+                       "attachment-view",
+                       "Attachment View",
+                       NULL,
+                       E_TYPE_ATTACHMENT_VIEW,
+                       G_PARAM_READWRITE |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
                PROP_FORMATTER,
                g_param_spec_pointer (
                        "formatter",
@@ -1875,8 +1636,25 @@ e_mail_display_init (EMailDisplay *display)
 
        display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
 
+       /* FIXME WK2: EAttachment::row-reference cannot be used. Steps:
+          a) open one message with attachments in the Mail window with the preview panel on
+          b) open the same message in a separate window
+             * observation - changing properties on the attachment are shown in both windows 
(expand/collapse/zoom)
+          c) close the separate window
+          d) click the arrow-down on the attachment to get its popup menu
+          A runtime warning:
+            evolution-mail-CRITICAL **: mail_display_attachment_select_path: assertion 
'gtk_tree_row_reference_valid (reference)' failed
+          is shown on the console and the popup menu is empty. Expand/collapse using the left part of the 
attachment button still works.
+       */
+       display->priv->attachment_store = E_ATTACHMENT_STORE (e_attachment_store_new ());
+       display->priv->attachment_view = e_weak_ref_new (NULL);
        display->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
(GDestroyNotify) g_variant_unref);
 
+       g_signal_connect (display->priv->attachment_store, "attachment-added",
+               G_CALLBACK (mail_display_attachment_added_cb), display);
+       g_signal_connect (display->priv->attachment_store, "attachment-removed",
+               G_CALLBACK (mail_display_attachment_removed_cb), display);
+
        /* Set invalid mode so that MODE property initialization is run
         * completely (see e_mail_display_set_mode) */
        display->priv->mode = E_MAIL_FORMATTER_MODE_INVALID;
@@ -1892,18 +1670,6 @@ e_mail_display_init (EMailDisplay *display)
                display, "process-mailto",
                G_CALLBACK (mail_display_process_mailto), NULL);
 #if 0
-       g_signal_connect (
-               display, "create-plugin-widget",
-               G_CALLBACK (mail_display_plugin_widget_requested), NULL);
-       e_signal_connect_notify (
-               display, "notify::uri",
-               G_CALLBACK (mail_display_uri_changed), NULL);
-       g_signal_connect (
-               display, "document-load-finished",
-               G_CALLBACK (setup_dom_bindings), NULL);
-       g_signal_connect (
-               display, "document-load-finished",
-               G_CALLBACK (initialize_web_view_colors), NULL);
        g_signal_connect_after (
                display, "drag-data-get",
                G_CALLBACK (mail_display_drag_data_get), display);
@@ -1921,10 +1687,7 @@ e_mail_display_init (EMailDisplay *display)
 
        g_signal_connect (
                display, "load-changed",
-               G_CALLBACK (setup_dom_bindings), NULL);
-       g_signal_connect (
-               display, "load-changed",
-               G_CALLBACK (mail_parts_bind_dom), NULL);
+               G_CALLBACK (mail_display_load_changed_cb), NULL);
 
        actions = e_web_view_get_action_group (E_WEB_VIEW (display), "mailto");
        gtk_action_group_add_actions (
@@ -1985,6 +1748,46 @@ e_mail_display_update_colors (EMailDisplay *display,
        g_free (color_value);
 }
 
+static void
+e_mail_display_claim_attachment (EMailFormatter *formatter,
+                                EAttachment *attachment,
+                                gpointer user_data)
+{
+       EMailDisplay *display = user_data;
+       GList *attachments;
+
+       g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+       g_return_if_fail (E_IS_ATTACHMENT (attachment));
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+       attachments = e_attachment_store_get_attachments (display->priv->attachment_store);
+
+       if (!g_list_find (attachments, attachment)) {
+               e_attachment_store_add_attachment (display->priv->attachment_store, attachment);
+
+               if (e_attachment_is_mail_note (attachment)) {
+                       CamelFolder *folder;
+                       const gchar *message_uid;
+
+                       folder = e_mail_part_list_get_folder (display->priv->part_list);
+                       message_uid = e_mail_part_list_get_message_uid (display->priv->part_list);
+
+                       if (folder && message_uid) {
+                               CamelMessageInfo *info;
+
+                               info = camel_folder_get_message_info (folder, message_uid);
+                               if (info) {
+                                       if (!camel_message_info_user_flag (info, E_MAIL_NOTES_USER_FLAG))
+                                               camel_message_info_set_user_flag (info, 
E_MAIL_NOTES_USER_FLAG, TRUE);
+                                       camel_message_info_unref (info);
+                               }
+                       }
+               }
+       }
+
+       g_list_free_full (attachments, g_object_unref);
+}
+
 GtkWidget *
 e_mail_display_new (EMailRemoteContent *remote_content)
 {
@@ -1993,6 +1796,34 @@ e_mail_display_new (EMailRemoteContent *remote_content)
                NULL);
 }
 
+EAttachmentStore *
+e_mail_display_get_attachment_store (EMailDisplay *display)
+{
+       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+       return display->priv->attachment_store;
+}
+
+void
+e_mail_display_set_attachment_view (EMailDisplay *display,
+                                   EAttachmentView *view)
+{
+       g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+       g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+
+       g_weak_ref_set (display->priv->attachment_view, view);
+
+       g_object_notify (G_OBJECT (display), "attachment-view");
+}
+
+EAttachmentView *
+e_mail_display_ref_attachment_view (EMailDisplay *display)
+{
+       g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+       return g_weak_ref_get (display->priv->attachment_view);
+}
+
 EMailFormatterMode
 e_mail_display_get_mode (EMailDisplay *display)
 {
@@ -2075,6 +1906,8 @@ e_mail_display_set_mode (EMailDisplay *display,
                        G_CALLBACK (e_mail_display_reload), display,
                NULL);
 
+       g_signal_connect (formatter, "claim-attachment", G_CALLBACK (e_mail_display_claim_attachment), 
display);
+
        e_mail_display_reload (display);
 
        g_object_notify (G_OBJECT (display), "mode");
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 63d7a6b..a850eab 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -62,6 +62,15 @@ struct _EMailDisplayClass {
 
 GType          e_mail_display_get_type         (void) G_GNUC_CONST;
 GtkWidget *    e_mail_display_new              (EMailRemoteContent *remote_content);
+EAttachmentStore *
+               e_mail_display_get_attachment_store
+                                               (EMailDisplay *display);
+void           e_mail_display_set_attachment_view
+                                               (EMailDisplay *display,
+                                                EAttachmentView *view);
+EAttachmentView *
+               e_mail_display_ref_attachment_view
+                                               (EMailDisplay *display);
 EMailFormatterMode
                e_mail_display_get_mode         (EMailDisplay *display);
 void           e_mail_display_set_mode         (EMailDisplay *display,
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index ce890e8..816227f 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -32,6 +32,7 @@
 #include "em-format/e-mail-formatter-print.h"
 
 #include "em-utils.h"
+#include "e-mail-display.h"
 #include "e-mail-ui-session.h"
 #include "e-mail-request.h"
 
@@ -56,6 +57,35 @@ e_mail_request_can_process_uri (EContentRequest *request,
        return g_ascii_strncasecmp (uri, "mail:", 5) == 0;
 }
 
+static void
+save_gicon_to_stream (GIcon *icon,
+                     gint size,
+                     GOutputStream *output_stream,
+                     gchar **out_mime_type)
+{
+       GtkIconInfo *icon_info;
+       GdkPixbuf *pixbuf;
+
+       if (size < 16)
+               size = 16;
+
+       icon_info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), icon, size, 
GTK_ICON_LOOKUP_FORCE_SIZE);
+       if (!icon_info)
+               return;
+
+       pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
+       if (pixbuf) {
+               if (gdk_pixbuf_save_to_stream (
+                       pixbuf, output_stream,
+                       "png", NULL, NULL, NULL)) {
+                       *out_mime_type = g_strdup ("image/png");
+               }
+               g_object_unref (pixbuf);
+       }
+
+       g_object_unref (icon);
+}
+
 static gboolean
 mail_request_process_mail_sync (EContentRequest *request,
                                SoupURI *suri,
@@ -120,6 +150,8 @@ mail_request_process_mail_sync (EContentRequest *request,
 
        if (context.mode == E_MAIL_FORMATTER_MODE_PRINTING)
                formatter = e_mail_formatter_print_new ();
+       else if (E_IS_MAIL_DISPLAY (requester))
+               formatter = g_object_ref (e_mail_display_get_formatter (E_MAIL_DISPLAY (requester)));
        else
                formatter = e_mail_formatter_new ();
 
@@ -130,6 +162,65 @@ mail_request_process_mail_sync (EContentRequest *request,
 
        output_stream = g_memory_output_stream_new_resizable ();
 
+       val = g_hash_table_lookup (uri_query, "attachment_icon");
+       if (val) {
+               gchar *attachment_id;
+
+               attachment_id = soup_uri_decode (val);
+               if (E_IS_MAIL_DISPLAY (requester)) {
+                       EMailDisplay *mail_display = E_MAIL_DISPLAY (requester);
+                       EAttachmentStore *attachment_store;
+                       GList *attachments, *link;
+
+                       attachment_store = e_mail_display_get_attachment_store (mail_display);
+                       attachments = e_attachment_store_get_attachments (attachment_store);
+                       for (link = attachments; link; link = g_list_next (link)) {
+                               EAttachment *attachment = link->data;
+                               gboolean can_use;
+
+                               tmp = g_strdup_printf ("%p", attachment);
+                               can_use = g_strcmp0 (tmp, attachment_id) == 0;
+                               g_free (tmp);
+
+                               if (can_use) {
+                                       GtkTreeRowReference *reference;
+
+                                       reference = e_attachment_get_reference (attachment);
+                                       if (gtk_tree_row_reference_valid (reference)) {
+                                               GtkTreePath *path;
+                                               GtkTreeIter iter;
+
+                                               path = gtk_tree_row_reference_get_path (reference);
+                                               if (gtk_tree_model_get_iter (GTK_TREE_MODEL 
(attachment_store), &iter, path)) {
+                                                       GIcon *icon = NULL;
+
+                                                       gtk_tree_model_get (GTK_TREE_MODEL 
(attachment_store), &iter,
+                                                               E_ATTACHMENT_STORE_COLUMN_ICON, &icon,
+                                                               -1);
+
+                                                       if (icon) {
+                                                               const gchar *size = g_hash_table_lookup 
(uri_query, "size");
+                                                               if (!size)
+                                                                       size = "16";
+
+                                                               save_gicon_to_stream (icon, atoi (size), 
output_stream, &use_mime_type);
+                                                       }
+                                               }
+                                               gtk_tree_path_free (path);
+                                       }
+
+                                       break;
+                               }
+                       }
+
+                       g_list_free_full (attachments, g_object_unref);
+               }
+
+               g_free (attachment_id);
+
+               goto no_part;
+       }
+
        val = g_hash_table_lookup (uri_query, "part_id");
        if (val != NULL) {
                EMailPart *part;
diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c
index 66a79c1..55a2891 100644
--- a/modules/mail/e-mail-shell-content.c
+++ b/modules/mail/e-mail-shell-content.c
@@ -43,6 +43,7 @@
 
 struct _EMailShellContentPrivate {
        EMailView *mail_view;
+       GtkWidget *attachment_bar; /* not referenced */
 };
 
 enum {
@@ -67,6 +68,27 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (
                E_TYPE_MAIL_READER,
                e_mail_shell_content_reader_init))
 
+static gboolean
+mail_shell_content_transform_num_attachments_to_visible_boolean_with_settings (GBinding *binding,
+                                                                              const GValue *from_value,
+                                                                              GValue *to_value,
+                                                                              gpointer user_data)
+{
+       GSettings *settings;
+       gboolean res = TRUE;
+
+       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+       if (g_settings_get_boolean (settings, "show-attachment-bar"))
+               res = e_attachment_store_transform_num_attachments_to_visible_boolean (binding, from_value, 
to_value, user_data);
+       else
+               g_value_set_boolean (to_value, FALSE);
+
+       g_clear_object (&settings);
+
+       return res;
+}
+
 static void
 reconnect_changed_event (EMailReader *child,
                          EMailReader *parent)
@@ -179,9 +201,11 @@ mail_shell_content_constructed (GObject *object)
        EMailShellContentPrivate *priv;
        EShellContent *shell_content;
        EShellView *shell_view;
+       EAttachmentStore *attachment_store;
+       EMailDisplay *display;
        GtkWindow *window;
-       GtkWidget *container;
        GtkWidget *widget;
+       GtkBox *vbox;
 
        priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
 
@@ -193,11 +217,15 @@ mail_shell_content_constructed (GObject *object)
 
        /* Build content widgets. */
 
-       container = GTK_WIDGET (object);
+       widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
+       gtk_container_add (GTK_CONTAINER (shell_content), widget);
+       gtk_widget_show (widget);
+
+       vbox = GTK_BOX (widget);
 
        widget = e_mail_paned_view_new (shell_view);
+       gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0);
 
-       gtk_container_add (GTK_CONTAINER (container), widget);
        priv->mail_view = g_object_ref (widget);
        gtk_widget_show (widget);
 
@@ -208,6 +236,21 @@ mail_shell_content_constructed (GObject *object)
                widget, "folder-loaded",
                G_CALLBACK (reconnect_folder_loaded_event), object);
 
+       display = e_mail_reader_get_mail_display (E_MAIL_READER (object));
+       attachment_store = e_mail_display_get_attachment_store (display);
+       widget = e_attachment_bar_new (attachment_store);
+       e_mail_display_set_attachment_view (display, E_ATTACHMENT_VIEW (widget));
+       gtk_box_pack_start (vbox, widget, FALSE, FALSE, 0);
+
+       priv->attachment_bar = widget;
+
+       e_binding_bind_property_full (
+               attachment_store, "num-attachments",
+               widget, "visible",
+               G_BINDING_SYNC_CREATE,
+               mail_shell_content_transform_num_attachments_to_visible_boolean_with_settings,
+               NULL, NULL, NULL);
+
        window = e_mail_reader_get_window (E_MAIL_READER (object));
        widget = e_mail_reader_get_message_list (E_MAIL_READER (object));
 
@@ -512,6 +555,14 @@ e_mail_shell_content_get_mail_view (EMailShellContent *mail_shell_content)
        return mail_shell_content->priv->mail_view;
 }
 
+GtkWidget *
+e_mail_shell_content_get_attachment_bar (EMailShellContent *mail_shell_content)
+{
+       g_return_val_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content), NULL);
+
+       return mail_shell_content->priv->attachment_bar;
+}
+
 EShellSearchbar *
 e_mail_shell_content_get_searchbar (EMailShellContent *mail_shell_content)
 {
diff --git a/modules/mail/e-mail-shell-content.h b/modules/mail/e-mail-shell-content.h
index db9ef85..f9dce15 100644
--- a/modules/mail/e-mail-shell-content.h
+++ b/modules/mail/e-mail-shell-content.h
@@ -67,6 +67,8 @@ GtkWidget *   e_mail_shell_content_new
                                        (EShellView *shell_view);
 EMailView *    e_mail_shell_content_get_mail_view
                                        (EMailShellContent *mail_shell_content);
+GtkWidget *    e_mail_shell_content_get_attachment_bar
+                                       (EMailShellContent *mail_shell_content);
 EShellSearchbar *
                e_mail_shell_content_get_searchbar
                                        (EMailShellContent *mail_shell_content);
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
index f1159cf..48cefd4 100644
--- a/modules/mail/e-mail-shell-view-actions.c
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -256,6 +256,25 @@ action_mail_create_search_folder_cb (GtkAction *action,
 }
 
 static void
+action_mail_attachment_bar_cb (GtkAction *action,
+                              EMailShellView *mail_shell_view)
+{
+       GtkWidget *attachment_bar;
+
+       attachment_bar = e_mail_shell_content_get_attachment_bar (mail_shell_view->priv->mail_shell_content);
+       if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+               EAttachmentStore *store;
+               guint num_attachments;
+
+               store = e_attachment_bar_get_store (E_ATTACHMENT_BAR (attachment_bar));
+               num_attachments = e_attachment_store_get_num_attachments (store);
+               gtk_widget_set_visible (attachment_bar, num_attachments > 0);
+       } else {
+               gtk_widget_hide (attachment_bar);
+       }
+}
+
+static void
 action_mail_download_finished_cb (CamelStore *store,
                                   GAsyncResult *result,
                                   EActivity *activity)
@@ -1991,6 +2010,14 @@ static GtkToggleActionEntry mail_toggle_entries[] = {
          NULL,  /* Handled by property bindings */
          TRUE },
 
+       { "mail-attachment-bar",
+         NULL,
+         N_("Show _Attachment Bar"),
+         NULL,
+         N_("Show Attachment Bar below the message preview pane when the message has attachments"),
+         G_CALLBACK (action_mail_attachment_bar_cb),
+         TRUE },
+
        { "mail-show-deleted",
          NULL,
          N_("Show _Deleted Messages"),
@@ -2300,6 +2327,11 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
                ACTION (MAIL_VFOLDER_UNMATCHED_ENABLE), "active",
                G_SETTINGS_BIND_DEFAULT);
 
+       g_settings_bind (
+               settings, "show-attachment-bar",
+               ACTION (MAIL_ATTACHMENT_BAR), "active",
+               G_SETTINGS_BIND_DEFAULT);
+
        g_object_unref (settings);
 
        /* Fine tuning. */
diff --git a/modules/mail/e-mail-shell-view-actions.h b/modules/mail/e-mail-shell-view-actions.h
index 866cc98..5459f73 100644
--- a/modules/mail/e-mail-shell-view-actions.h
+++ b/modules/mail/e-mail-shell-view-actions.h
@@ -34,6 +34,8 @@
        E_SHELL_WINDOW_ACTION ((window), "mail-account-refresh")
 #define E_SHELL_WINDOW_ACTION_MAIL_ADD_SENDER(window) \
        E_SHELL_WINDOW_ACTION ((window), "mail-add-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_ATTACHMENT_BAR(window) \
+       E_SHELL_WINDOW_ACTION ((window), "mail-attachment-bar")
 #define E_SHELL_WINDOW_ACTION_MAIL_CARET_MODE(window) \
        E_SHELL_WINDOW_ACTION ((window), "mail-caret-mode")
 #define E_SHELL_WINDOW_ACTION_MAIL_CHECK_FOR_JUNK(window) \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 643b2a7..6ccae22 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -191,6 +191,7 @@ e-util/e-charset-combo-box.c
 e-util/e-client-cache.c
 e-util/e-color-chooser-widget.c
 e-util/e-color-combo.c
+e-util/e-content-editor.c
 e-util/e-dateedit.c
 e-util/e-datetime-format.c
 e-util/e-dialog-utils.c
diff --git a/ui/evolution-mail.ui b/ui/evolution-mail.ui
index b58d222..bf26e03 100644
--- a/ui/evolution-mail.ui
+++ b/ui/evolution-mail.ui
@@ -19,6 +19,7 @@
       <placeholder name='view-custom-menus'>
         <menu action='mail-preview-menu'>
           <menuitem action='mail-preview'/>
+          <menuitem action='mail-attachment-bar'/>
           <separator/>
           <menuitem action='mail-view-classic'/>
           <menuitem action='mail-view-vertical'/>
diff --git a/web-extensions/e-dom-utils.c b/web-extensions/e-dom-utils.c
index f855c3f..2a05697 100644
--- a/web-extensions/e-dom-utils.c
+++ b/web-extensions/e-dom-utils.c
@@ -962,38 +962,11 @@ gboolean
 e_dom_utils_element_exists (WebKitDOMDocument *document,
                             const gchar *element_id)
 {
-       WebKitDOMHTMLCollection *frames;
-       gboolean element_exists = FALSE;
-       gulong ii, length;
-
-       /* Try to look up the element in this DOM document */
-       if (webkit_dom_document_get_element_by_id (document, element_id))
-               return TRUE;
-
-       /* If the element is not here then recursively scan all frames */
-       frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
-       length = webkit_dom_html_collection_get_length (frames);
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMHTMLIFrameElement *iframe;
-               WebKitDOMDocument *content_document;
-
-               iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
-                       webkit_dom_html_collection_item (frames, ii));
-
-               content_document = webkit_dom_html_iframe_element_get_content_document (iframe);
-               if (!content_document)
-                       continue;
-
-               element_exists = e_dom_utils_element_exists (content_document, element_id);
+       WebKitDOMElement *element;
 
-               if (element_exists) {
-                       g_object_unref (frames);
-                       return TRUE;
-               }
-       }
+       element = e_dom_utils_find_element_by_id (document, element_id);
 
-       g_object_unref (frames);
-       return FALSE;
+       return element != NULL;
 }
 
 gchar *
@@ -1066,7 +1039,7 @@ e_dom_utils_element_set_inner_html (WebKitDOMDocument *document,
 {
        WebKitDOMElement *element;
 
-       element = webkit_dom_document_get_element_by_id (document, element_id);
+       element = e_dom_utils_find_element_by_id (document, element_id);
 
        if (!element)
                return;
@@ -1080,7 +1053,7 @@ e_dom_utils_remove_element (WebKitDOMDocument *document,
 {
        WebKitDOMElement *element;
 
-       element = webkit_dom_document_get_element_by_id (document, element_id);
+       element = e_dom_utils_find_element_by_id (document, element_id);
 
        if (!element)
                return;
@@ -1096,8 +1069,13 @@ e_dom_utils_element_remove_child_nodes (WebKitDOMDocument *document,
                                         const gchar *element_id)
 {
        WebKitDOMNode *node;
+       WebKitDOMElement *element;
 
-       node = WEBKIT_DOM_NODE (webkit_dom_document_get_element_by_id (document, element_id));
+       element = e_dom_utils_find_element_by_id (document, element_id);
+       if (!element)
+               return;
+
+       node = WEBKIT_DOM_NODE (element);
 
        if (!node)
                return;
@@ -1117,7 +1095,7 @@ e_dom_utils_hide_element (WebKitDOMDocument *document,
 {
        WebKitDOMElement *element;
 
-       element = webkit_dom_document_get_element_by_id (document, element_id);
+       element = e_dom_utils_find_element_by_id (document, element_id);
 
        if (!element)
                return;
@@ -1132,13 +1110,12 @@ e_dom_utils_element_is_hidden (WebKitDOMDocument *document,
 {
        WebKitDOMElement *element;
 
-       element = webkit_dom_document_get_element_by_id (document, element_id);
+       element = e_dom_utils_find_element_by_id (document, element_id);
 
        if (!element)
                return FALSE;
 
-       return webkit_dom_html_element_get_hidden (
-               WEBKIT_DOM_HTML_ELEMENT (element));
+       return webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (element));
 }
 
 static void
diff --git a/web-extensions/e-web-extension.c b/web-extensions/e-web-extension.c
index b0ebdb9..b4e9784 100644
--- a/web-extensions/e-web-extension.c
+++ b/web-extensions/e-web-extension.c
@@ -69,6 +69,25 @@ static const char introspection_xml[] =
 "      <arg type='i' name='position_width' direction='out'/>"
 "      <arg type='i' name='position_height' direction='out'/>"
 "    </signal>"
+"    <method name='SetElementHidden'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='b' name='hidden' direction='in'/>"
+"    </method>"
+"    <method name='SetElementStyleProperty'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='s' name='property_name' direction='in'/>"
+"      <arg type='s' name='value' direction='in'/>"
+"      <arg type='s' name='priority' direction='in'/>"
+"    </method>"
+"    <method name='SetElementAttribute'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='element_id' direction='in'/>"
+"      <arg type='s' name='namespace_uri' direction='in'/>"
+"      <arg type='s' name='qualified_name' direction='in'/>"
+"      <arg type='s' name='value' direction='in'/>"
+"    </method>"
 "    <signal name='HeadersCollapsed'>"
 "      <arg type='b' name='expanded' direction='out'/>"
 "    </signal>"
@@ -334,6 +353,146 @@ handle_method_call (GDBusConnection *connection,
                }
 
                g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SetElementHidden") == 0) {
+               const gchar *element_id = NULL;
+               gboolean hidden = FALSE;
+
+               g_variant_get (parameters, "(t&sb)", &page_id, &element_id, &hidden);
+
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               if (!element_id || !*element_id) {
+                       g_warn_if_fail (element_id && *element_id);
+               } else {
+                       document = webkit_web_page_get_dom_document (web_page);
+
+                       /* A secret short-cut, to not have two functions for basically the same thing ("hide 
attachment" and "hide element") */
+                       if (!hidden && g_str_has_prefix (element_id, "attachment-wrapper-")) {
+                               WebKitDOMElement *element;
+
+                               element = e_dom_utils_find_element_by_id (document, element_id);
+
+                               if (WEBKIT_DOM_IS_HTML_ELEMENT (element) &&
+                                   webkit_dom_element_get_child_element_count (element) == 0) {
+                                       gchar *inner_html_data;
+
+                                       inner_html_data = webkit_dom_element_get_attribute (element, 
"inner-html-data");
+                                       if (inner_html_data && *inner_html_data) {
+                                               WebKitDOMHTMLElement *html_element;
+
+                                               html_element = WEBKIT_DOM_HTML_ELEMENT (element);
+                                               webkit_dom_html_element_set_inner_html (html_element, 
inner_html_data, NULL);
+
+                                               webkit_dom_element_remove_attribute (element, 
"inner-html-data");
+                                       }
+
+                                       g_free (inner_html_data);
+                               }
+                       }
+
+                       e_dom_utils_hide_element (document, element_id, hidden);
+               }
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SetElementStyleProperty") == 0) {
+               const gchar *element_id = NULL, *property_name = NULL, *value = NULL, *priority = NULL;
+
+               g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &property_name, &value, 
&priority);
+
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               if (!element_id || !*element_id || !property_name || !*property_name) {
+                       g_warn_if_fail (element_id && *element_id);
+                       g_warn_if_fail (property_name && *property_name);
+               } else {
+                       WebKitDOMElement *element;
+                       gboolean use_child = FALSE;
+                       gchar *tmp = NULL;
+
+                       /* element_id can be also of the form: "id::child", where the change will
+                          be done on the first child of it */
+                       use_child = g_str_has_suffix (element_id, "::child");
+                       if (use_child) {
+                               tmp = g_strdup (element_id);
+                               tmp[strlen (tmp) - 7] = '\0';
+
+                               element_id = tmp;
+                       }
+
+                       document = webkit_web_page_get_dom_document (web_page);
+                       element = e_dom_utils_find_element_by_id (document, element_id);
+
+                       if (use_child && element)
+                               element = webkit_dom_element_get_first_element_child (element);
+
+                       if (element) {
+                               WebKitDOMCSSStyleDeclaration *css;
+
+                               css = webkit_dom_element_get_style (element);
+
+                               if (value && *value)
+                                       webkit_dom_css_style_declaration_set_property (css, property_name, 
value, priority, NULL);
+                               else
+                                       g_free (webkit_dom_css_style_declaration_remove_property (css, 
property_name, NULL));
+
+                               g_clear_object (&css);
+                       }
+
+                       g_free (tmp);
+               }
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "SetElementAttribute") == 0) {
+               const gchar *element_id = NULL, *namespace_uri = NULL, *qualified_name = NULL, *value = NULL;
+
+               g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &namespace_uri, 
&qualified_name, &value);
+
+               web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+               if (!web_page)
+                       return;
+
+               if (!element_id || !*element_id || !qualified_name || !*qualified_name) {
+                       g_warn_if_fail (element_id && *element_id);
+                       g_warn_if_fail (qualified_name && *qualified_name);
+               } else {
+                       WebKitDOMElement *element;
+                       gboolean use_child = FALSE;
+                       gchar *tmp = NULL;
+
+                       /* element_id can be also of the form: "id::child", where the change will
+                          be done on the first child of it */
+                       use_child = g_str_has_suffix (element_id, "::child");
+                       if (use_child) {
+                               tmp = g_strdup (element_id);
+                               tmp[strlen (tmp) - 7] = '\0';
+
+                               element_id = tmp;
+                       }
+
+                       if (namespace_uri && !*namespace_uri)
+                               namespace_uri = NULL;
+
+                       document = webkit_web_page_get_dom_document (web_page);
+                       element = e_dom_utils_find_element_by_id (document, element_id);
+
+                       if (use_child && element)
+                               element = webkit_dom_element_get_first_element_child (element);
+
+                       if (element) {
+                               if (value && *value)
+                                       webkit_dom_element_set_attribute_ns (element, namespace_uri, 
qualified_name, value, NULL);
+                               else
+                                       webkit_dom_element_remove_attribute_ns (element, namespace_uri, 
qualified_name);
+                       }
+
+                       g_free (tmp);
+               }
+
+               g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DocumentHasSelection") == 0) {
                gboolean has_selection;
 



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