[evolution/webkit: 154/171] Single-webview transition - handle resizing and showing/hiding of embedded widgets



commit e3d8c7b348dbd769b164caa383f9469bb8458027
Author: Dan VrÃtil <dvratil redhat com>
Date:   Tue Feb 14 14:59:21 2012 +0100

    Single-webview transition - handle resizing and showing/hiding of embedded widgets
    
    EMailDisplay now handles resizing and displaying embedded widgets.

 mail/e-mail-display.c         |  245 +++++++++++++++++++++++++++++++---------
 mail/e-mail-request.c         |    8 +-
 mail/em-format-html-display.c |   20 +++-
 3 files changed, 210 insertions(+), 63 deletions(-)
---
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index a551da0..328a0ec 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -496,7 +496,6 @@ mail_display_resource_requested (WebKitWebView *web_view,
                 }
 
                 new_uri = g_strconcat ("evo-", uri, NULL);
-                /* Don't free, will be freed when the hash table is destroyed */
                 mail_uri = em_format_build_mail_uri (formatter->folder,
                                 formatter->message_uid, NULL, NULL);
 
@@ -530,52 +529,91 @@ mail_display_resource_requested (WebKitWebView *web_view,
         }
 }
 
+static WebKitDOMElement*
+find_element_by_id (WebKitDOMDocument *document,
+                    const gchar *id)
+{
+        WebKitDOMNodeList *frames;
+        WebKitDOMElement *element;
+        gulong i;
+
+        /* Try to look up the element in this DOM document */
+        element = webkit_dom_document_get_element_by_id (document, id);
+        if (element)
+                return element;
+
+        /* If the element is not here then recursively scan all frames */
+        frames = webkit_dom_document_get_elements_by_tag_name(document, "iframe");
+        for (i = 0; i < webkit_dom_node_list_get_length (frames); i++)
+        {
+                WebKitDOMHTMLIFrameElement *iframe =
+                        WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+                                webkit_dom_node_list_item (frames, i));
+
+                WebKitDOMDocument *frame_doc =
+                        webkit_dom_html_iframe_element_get_content_document (iframe);
+
+                WebKitDOMElement *el =
+                        find_element_by_id (frame_doc, id);
+
+                if (el)
+                        return el;
+        }
+
+        return NULL;
+}
+
 static void
 mail_display_plugin_widget_resize (GObject *object,
                                    gpointer dummy,
 				   EMailDisplay *display)
 {
         GtkWidget *widget;
-	WebKitDOMDocument *document;
-	WebKitDOMNodeList *nodes;
-	gint i;
-	gchar *puri_uri;
+        WebKitDOMElement *parent_element;
+	const gchar *uri;
+        gchar *dim;
 	gint height;
 
         widget = GTK_WIDGET (object);
 	gtk_widget_get_preferred_height (widget, &height, NULL);
+	uri = g_object_get_data (object, "uri");
+        parent_element = g_object_get_data (object, "parent_element");
 
-	puri_uri = g_object_get_data (G_OBJECT (widget), "uri");
-
-	document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
-	nodes = webkit_dom_document_get_elements_by_tag_name (document, "object");
-
-        /* Find <object> with matching URI and resize it */
-	for (i = 0; i < webkit_dom_node_list_get_length (nodes); i++) {
-
-		WebKitDOMNode *node = webkit_dom_node_list_item (nodes, i);
-
-		gchar *uri =webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "data");
-
-		if (g_strcmp0 (uri, puri_uri) == 0) {
-
-			gchar *dim;
+        if (!parent_element) {
+                WebKitDOMDocument *document;
+                WebKitDOMElement *doc_element;
 
-			dim = g_strdup_printf ("%d", height);
-			webkit_dom_html_object_element_set_height (
-				WEBKIT_DOM_HTML_OBJECT_ELEMENT (node), dim);
-			g_free (dim);
+                document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
+                parent_element = find_element_by_id (document, uri);
 
-			g_free (uri);
+                if (!parent_element) {
+                        g_warning ("No parent <object> for widget %s", uri);
+                        return;
+                }
 
-			gtk_widget_queue_draw (GTK_WIDGET (display));
-			gtk_widget_queue_draw (widget);
+                /* Store the parent element in the object so that we don't have
+                 * to look it up every time */
+                g_object_set_data_full (object, "parent_element",
+                        g_object_ref (parent_element),
+                        (GDestroyNotify) g_object_unref);
+
+                /* Hide the widget when the document itself gets
+                 * invisible (usually when parent <iframe> is hidden) */
+                doc_element = webkit_dom_document_get_document_element (document);
+                g_object_bind_property (
+                        doc_element, "hidden",
+                        widget, "visible",
+                        G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+        }
 
-			return;
-		}
+        /* Int -> Str */
+	dim = g_strdup_printf ("%d", height);
+        webkit_dom_html_object_element_set_height (
+                WEBKIT_DOM_HTML_OBJECT_ELEMENT (parent_element), dim);
+        g_free (dim);
 
-		g_free (uri);
-	}
+	gtk_widget_queue_draw (GTK_WIDGET (display));
+	gtk_widget_queue_draw (widget);
 }
 
 static void
@@ -585,6 +623,28 @@ mail_display_plugin_widget_realize_cb (GtkWidget *widget,
         mail_display_plugin_widget_resize (G_OBJECT (widget), NULL, user_data);
 }
 
+static void
+bind_iframe_document_visibility (GObject *object,
+                                 GParamSpec *pspec,
+                                 gpointer user_data)
+{
+        /* Change in visibility of <iframe> does not change "hidden" property
+         * of DOM document it contains, thus we have to bind it manually. */
+        WebKitDOMHTMLIFrameElement *iframe =
+                WEBKIT_DOM_HTML_IFRAME_ELEMENT (object);
+
+        WebKitDOMDocument *document =
+                webkit_dom_html_iframe_element_get_content_document (iframe);
+
+        WebKitDOMElement *doc_element = 
+                webkit_dom_document_get_document_element (document);
+
+        g_object_bind_property (
+                iframe, "hidden",
+                doc_element, "hidden",
+                G_BINDING_SYNC_CREATE);
+}
+
 static GtkWidget*
 mail_display_plugin_widget_requested (WebKitWebView *web_view,
                                       gchar *mime_type,
@@ -602,8 +662,6 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
         if (!puri_uri || !g_str_has_prefix (uri, "mail://"))
                 return NULL;
 
-        d(printf("Created widget %s\n", puri_uri));
-
         display = E_MAIL_DISPLAY (web_view);
         emf = (EMFormat *) display->priv->formatter;
 
@@ -617,39 +675,115 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
 	else
 		widget = NULL;
 
-	if (widget) {
-		gtk_widget_show (widget);
-		g_object_set_data_full (G_OBJECT (widget), "uri",
-			g_strdup (puri_uri), (GDestroyNotify) g_free);
+	if (!widget)
+                return NULL;
+
+        d(printf("Created widget %s\n", puri_uri));
+
+        if (E_IS_ATTACHMENT_BUTTON (widget)) {
+                /* Attachment button has URI different then the actual PURI because
+                 * that URI identifies the attachment itself */
+                gchar *button_uri = g_strconcat (puri_uri, ".attachment_button", NULL);
+                g_object_set_data_full (G_OBJECT (widget), "uri",
+                        button_uri, (GDestroyNotify) g_free);
+        } else {
+                g_object_set_data_full (G_OBJECT (widget), "uri",
+                        g_strdup (puri_uri), (GDestroyNotify) g_free);
+        }
+
 
-                g_signal_connect (widget, "realize",
-                        G_CALLBACK (mail_display_plugin_widget_realize_cb), display);
-                g_signal_connect (widget, "size-allocate",
+        /* Resizing a GtkWidget requires changing size of parent
+         * <object> HTML element in DOM. */
+        g_signal_connect (widget, "realize",
+                G_CALLBACK (mail_display_plugin_widget_realize_cb), display);
+        g_signal_connect (widget, "size-allocate",
+                G_CALLBACK (mail_display_plugin_widget_resize), display);
+
+        if (E_IS_MAIL_ATTACHMENT_BAR (widget)) {
+
+                /* When EMailAttachmentBar is expanded/collapsed it does not
+                 * emit size-allocate signal despite it changes it's height. */
+                GtkWidget *box = NULL;
+
+                /* Only when packed in box, EMailAttachmentBar reports correct 
+                 * height */
+                box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+                gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+
+                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);
 
-                /* Some special handling of resizing of attachment bar. */
-                if (E_IS_MAIL_ATTACHMENT_BAR (widget)) {
-                        GtkWidget *box = NULL;
+                widget = box;
 
-                        /* Only when packed in box, EMailAttachmentBar reports
-                         * correct height */
-                        box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-                        gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+        } else if (E_IS_ATTACHMENT_BUTTON (widget)) {
 
-                        /* Change <object> height whenever height of
-                         * the attachment bar changes */
-                        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);
+                /* Bind visibility of DOM element containing related
+                 * attachment with 'expanded' property of this
+                 * attachment button. */
+                WebKitDOMElement *attachment;
+                WebKitDOMDocument *document;
 
-                        widget = box;
+                document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
+                attachment = find_element_by_id (document, puri_uri);
+                if (!attachment) {
+                        e_attachment_button_set_expandable (
+                                E_ATTACHMENT_BUTTON (widget), FALSE);
+                } else {
+                        WebKitDOMNodeList *children;
+                        const CamelContentDisposition *disposition;
+                        gulong i;
+
+                        g_object_bind_property (
+                                widget, "expanded",
+                                attachment, "hidden",
+                                G_BINDING_SYNC_CREATE |
+                                G_BINDING_INVERT_BOOLEAN);
+
+                        children =
+                                webkit_dom_element_get_elements_by_tag_name(
+                                        attachment, "iframe");
+
+                        /* Try to find an <iframe> within the attachment (usually
+                         * embedded message) and bind it's "hidden" property with
+                         * it's inner DOM document "hidden" property. */
+                        for (i = 0; i < webkit_dom_node_list_get_length (children); i++) {
+
+                                WebKitDOMElement *child =
+                                        WEBKIT_DOM_ELEMENT (
+                                                webkit_dom_node_list_item (children, i));
+
+                                if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (child))
+                                        continue;
+
+                                /* Re-bind whenever content of the iframe changes */
+                                g_signal_connect (child, "notify::src",
+                                        G_CALLBACK (bind_iframe_document_visibility),
+                                        NULL);
+
+                                /* Create initial binding */
+                                bind_iframe_document_visibility (
+                                        G_OBJECT (child), NULL, NULL);
+                        }
+
+                        /* Expand inlined attachments */
+                        disposition =
+                                camel_mime_part_get_content_disposition (puri->part);
+                        if (disposition &&
+                            g_ascii_strncasecmp (
+                                disposition->disposition, "inline", 6) == 0) {
+
+                                e_attachment_button_set_expanded (
+                                        E_ATTACHMENT_BUTTON (widget), TRUE);
+                        }
                 }
-	}
+        }
 
         return widget;
 }
 
+
 static void
 mail_display_headers_collapsed_state_changed (EWebView *web_view,
 					      size_t arg_count,
@@ -674,6 +808,7 @@ mail_display_install_js_callbacks (WebKitWebView *web_view,
 
 	e_web_view_install_js_callback (E_WEB_VIEW (web_view), "headers_collapsed",
 		(EWebViewJSFunctionCallback) mail_display_headers_collapsed_state_changed, user_data);
+
 }
 
 static void
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index 31a5cc5..5b62e36 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -14,7 +14,7 @@
 #include <e-util/e-icon-factory.h>
 #include <e-util/e-util.h>
 
-#define d(x) x
+#define d(x)
 #define dd(x)
 
 G_DEFINE_TYPE (EMailRequest, e_mail_request, SOUP_TYPE_REQUEST)
@@ -96,7 +96,11 @@ handle_mail_request (GSimpleAsyncResult *res,
 		g_byte_array_append (ba, (guchar*) data, strlen (data));
 		g_free (data);
 	} else {
-		dd(printf("%s", ba->data));
+		dd({
+                        gchar *d = g_strndup ((gchar *) ba->data, ba->len);
+                        printf("%s", d);
+                        g_free (d);
+                });
 	}
 
 	stream = g_memory_input_stream_new_from_data ((gchar*) ba->data, ba->len, NULL);
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index f8cd9bc..2bfe15f 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -709,7 +709,7 @@ efhd_write_attachment_bar (EMFormat *emf,
 	str = g_strdup_printf (
                 "<object type=\"application/x-attachment-bar\" "
 			"height=\"20\" width=\"100%%\" "
-                        "data=\"%s\"></object>", puri->uri);
+                        "id=\"%s\"data=\"%s\"></object>", puri->uri, puri->uri);
 
 	camel_stream_write_string (stream, str, cancellable, NULL);
 
@@ -725,6 +725,7 @@ efhd_write_attachment (EMFormat *emf,
 {
         gchar *str, *desc;
         const gchar *mime_type;
+        gchar *button_id;
 
         EMFormatAttachmentPURI *efa = (EMFormatAttachmentPURI *) puri;
 
@@ -733,25 +734,29 @@ efhd_write_attachment (EMFormat *emf,
         else
                 mime_type = efa->snoop_mime_type;
 
+        button_id = g_strconcat (puri->uri, ".attachment_button", NULL);
+
         desc = em_format_describe_part (puri->part, mime_type);
 	str = g_strdup_printf (
+                "<div class=\"attachment\">"
                 "<table width=\"100%%\" border=\"0\">"
                 "<tr valign=\"middle\">"
                 "<td align=\"left\" width=\"100\">"
                 "<object type=\"application/x-attachment-button\" "
-		"height=\"20\" width=\"100\" data=\"%s\"></object>"
+		"height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>"
                 "</td>"
                 "<td align=\"left\">%s</td>"
-                "</tr>"
-                "</table>", puri->uri, desc);
+                "</tr>", puri->uri, button_id, desc);
 
         camel_stream_write_string (stream, str, cancellable, NULL);
         g_free (desc);
+        g_free (button_id);
 
         /* If we know how to write the attachment, then do it */
         if (efa->handle && efa->handle->write_func) {
 
                 str = g_strdup_printf (
+                        "<tr><td colspan=\"2\">"
                         "<div class=\"attachment-wrapper\" id=\"%s\">",
                         puri->uri);
 
@@ -760,8 +765,10 @@ efhd_write_attachment (EMFormat *emf,
 
                 efa->handle->write_func (emf, puri, stream, info, cancellable);
 
-                camel_stream_write_string (stream, "</div>", cancellable, NULL);
+                camel_stream_write_string (stream, "</div></td></tr>", cancellable, NULL);
         }
+
+        camel_stream_write_string (stream, "</table></div>", cancellable, NULL);
 }
 
 static void
@@ -776,7 +783,7 @@ efhd_write_secure_button (EMFormat *emf,
         str = g_strdup_printf (
                 "<object type=\"application/x-secure-button\" "
                 "height=\"20\" width=\"100%%\" "
-                "data=\"%s\"></object>", puri->uri);
+                "data=\"%s\" id=\"%s\"></object>", puri->uri, puri->uri);
 
         camel_stream_write_string (stream, str, cancellable, NULL);
 
@@ -990,6 +997,7 @@ efhd_attachment_button (EMFormat *emf,
 	}
 
 	widget = e_attachment_button_new ();
+        g_object_set_data (G_OBJECT (widget), "uri", puri->uri);
 	e_attachment_button_set_attachment (
 		E_ATTACHMENT_BUTTON (widget), info->attachment);
         e_attachment_button_set_view (



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