[evolution/webkit: 157/196] When an <iframe> is hidden, _hide() all GtkWidget it contains
- From: Dan VrÃtil <dvratil src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/webkit: 157/196] When an <iframe> is hidden, _hide() all GtkWidget it contains
- Date: Tue, 27 Mar 2012 16:13:55 +0000 (UTC)
commit 5f925416fe5b35dfc533a5b00452457876c4b714
Author: Dan VrÃtil <dvratil redhat com>
Date: Tue Feb 21 10:37:06 2012 +0100
When an <iframe> is hidden, _hide() all GtkWidget it contains
When an attachment button is collapsed and a related <iframe> which contains the attachment
(message/rfc822 or text/html) is hidden, the all GtkWidget within the <iframe> must
be hidden too. Otherwise they are rendered on the WebView randomly because WebKit is unable
to anchor them to the <object> element.
<object> elements with a document (nor the document itself actually) within an <iframe> are
not considered to be hidden when the iframe itself is hidden, therefor we must use this
quite complex bindings.
mail/e-mail-display.c | 302 +++++++++++++++++++++++++++++++++++++------------
mail/em-format-html.c | 4 +-
2 files changed, 230 insertions(+), 76 deletions(-)
---
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 444150b..0f83555 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -535,7 +535,7 @@ find_element_by_id (WebKitDOMDocument *document,
{
WebKitDOMNodeList *frames;
WebKitDOMElement *element;
- gulong i;
+ gulong i, length;
/* Try to look up the element in this DOM document */
element = webkit_dom_document_get_element_by_id (document, id);
@@ -544,8 +544,9 @@ find_element_by_id (WebKitDOMDocument *document,
/* 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++)
- {
+ length = webkit_dom_node_list_get_length (frames);
+ for (i = 0; i < length; i++){
+
WebKitDOMHTMLIFrameElement *iframe =
WEBKIT_DOM_HTML_IFRAME_ELEMENT (
webkit_dom_node_list_item (frames, i));
@@ -570,44 +571,21 @@ mail_display_plugin_widget_resize (GObject *object,
{
GtkWidget *widget;
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");
- if (!parent_element) {
- WebKitDOMDocument *document;
- WebKitDOMElement *doc_element;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
- parent_element = find_element_by_id (document, uri);
-
- if (!parent_element) {
- g_warning ("No parent <object> for widget %s", uri);
- return;
- }
-
- /* 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);
- }
+ if (!parent_element)
+ return;
/* 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);
@@ -620,29 +598,187 @@ static void
mail_display_plugin_widget_realize_cb (GtkWidget *widget,
gpointer user_data)
{
+ /* Initial resize of the <object> element when the widget
+ * is displayed for the first time. */
mail_display_plugin_widget_resize (G_OBJECT (widget), NULL, user_data);
}
static void
-bind_iframe_document_visibility (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+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 || !*uri)
+ return;
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
+ element = find_element_by_id (document, uri);
+
+ if (!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_full (G_OBJECT (widget), "parent_element",
+ g_object_ref (element), (GDestroyNotify) g_object_unref);
+ g_object_set_data_full (G_OBJECT (element), "widget",
+ g_object_ref (widget), (GDestroyNotify) g_object_unref);
+}
+
+static void
+attachment_button_expanded (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
+ WebKitDOMElement *attachment = user_data;
+ WebKitDOMCSSStyleDeclaration *css;
+ gboolean expanded;
+
+ expanded = e_attachment_button_get_expanded (button) &&
+ gtk_widget_get_visible (GTK_WIDGET (button));
+
+ /* Show or hide the DIV which contains the attachment (iframe, image...) */
+ css = webkit_dom_element_get_style (attachment);
+ webkit_dom_css_style_declaration_set_property (
+ css, "display", expanded ? "block" : "none", "", NULL);
+}
+
+static void
+constraint_widget_visibility (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GtkWidget *widget = GTK_WIDGET (object);
+ EAttachmentButton *button = user_data;
+
+ gboolean can_show = e_attachment_button_get_expanded (button);
+ gboolean is_visible = gtk_widget_get_visible (widget);
+
+ if (is_visible && !can_show)
+ gtk_widget_hide (widget);
+ else if (!is_visible && can_show)
+ gtk_widget_show (widget);
+
+ /* Otherwise it's OK */
+}
+
+static void
+bind_iframe_content_visibility (EAttachmentButton *button,
+ WebKitDOMElement *iframe)
{
- /* 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;
+ WebKitDOMNodeList *nodes;
+ gulong i, length;
+
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (iframe))
+ return;
+
+ document = webkit_dom_html_iframe_element_get_content_document(
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+ nodes = webkit_dom_document_get_elements_by_tag_name (document, "object");
+ length = webkit_dom_node_list_get_length (nodes);
+ d(printf("Found %ld objects within iframe %s\n", length,
+ webkit_dom_html_iframe_element_get_name (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe))));
- WebKitDOMDocument *document =
- webkit_dom_html_iframe_element_get_content_document (iframe);
+ /* Iterate through all <object>s and bind visibility of their widget
+ * with expanded-state of related attachment button */
+ for (i = 0; i < length; i++) {
- WebKitDOMElement *doc_element =
- webkit_dom_document_get_document_element (document);
+ WebKitDOMNode *node = webkit_dom_node_list_item (nodes, i);
+ GtkWidget *widget;
- g_object_bind_property (
- iframe, "hidden",
- doc_element, "hidden",
- G_BINDING_SYNC_CREATE);
+ widget = g_object_get_data (G_OBJECT (node), "widget");
+ if (!widget)
+ continue;
+
+ d(printf("Binding visibility of widget %s with button %s\n",
+ (gchar *) g_object_get_data (G_OBJECT (widget), "uri"),
+ (gchar *) g_object_get_data (G_OBJECT (button), "uri")));
+
+ g_object_bind_property (
+ button, "expanded",
+ widget, "visible",
+ G_BINDING_SYNC_CREATE);
+
+ /* Ensure that someone won't attempt to _show() the widget when
+ * it is supposed to be hidden and vice versa. */
+ g_signal_connect (widget, "notify::visible",
+ G_CALLBACK (constraint_widget_visibility), button);
+ }
+}
+
+static void
+bind_attachment_iframe_visibility (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ WebKitWebFrame *webframe;
+ const gchar *frame_name;
+ gchar *button_uri;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *attachment;
+ WebKitDOMElement *button_element;
+ WebKitDOMNodeList *nodes;
+ gulong i, length;
+ GtkWidget *button;
+
+ /* Whenever an <iframe> is loaded, bind visibility of all GtkWidgets
+ * the document within the <iframe> contains with "expanded" property
+ * of the EAttachmentButton */
+
+ webframe = WEBKIT_WEB_FRAME (object);
+ if (webkit_web_frame_get_load_status (webframe) != WEBKIT_LOAD_FINISHED)
+ return;
+
+ frame_name = webkit_web_frame_get_name (webframe);
+
+ d(printf("Rebinding visibility of frame %s because it's URL changed\n",
+ frame_name));
+
+ /* Get DOMDocument of the main document */
+ document = webkit_web_view_get_dom_document (
+ webkit_web_frame_get_web_view (webframe));
+ if (!document)
+ return;
+
+ /* Find the <DIV> containing the <iframe> and related EAttachmentButton
+ * within the DOM */
+ attachment = find_element_by_id (document, frame_name);
+ if (!attachment)
+ return;
+
+ button_uri = g_strconcat (frame_name, ".attachment_button", NULL);
+ button_element = find_element_by_id (document, button_uri);
+ if (!button_element)
+ return;
+
+ button = g_object_get_data (G_OBJECT (button_element), "widget");
+
+ /* Get <iframe> representing the attachment content */
+ nodes = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe");
+ length = webkit_dom_node_list_get_length (nodes);
+ for (i = 0; i < length; i++) {
+
+ WebKitDOMNode *node =
+ webkit_dom_node_list_item (nodes, i);
+
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node))
+ continue;
+
+ /* Bind visibility of all GtkWidget within the
+ * iframe with "expanded" property of the button */
+ bind_iframe_content_visibility(
+ E_ATTACHMENT_BUTTON (button),
+ WEBKIT_DOM_ELEMENT (node));
+ }
}
static GtkWidget*
@@ -691,6 +827,8 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
g_strdup (puri_uri), (GDestroyNotify) g_free);
}
+ /* Set widget's <object> container as GObject data "parent_element" */
+ plugin_widget_set_parent_element (widget, display);
/* Resizing a GtkWidget requires changing size of parent
* <object> HTML element in DOM. */
@@ -715,6 +853,9 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
g_signal_connect (widget, "notify::active-view",
G_CALLBACK (mail_display_plugin_widget_resize), display);
+ /* Show the EAttachmentBar but not the containing layout */
+ gtk_widget_show (widget);
+
widget = box;
} else if (E_IS_ATTACHMENT_BUTTON (widget)) {
@@ -731,40 +872,38 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
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(
+ WebKitDOMNodeList *nodes;
+ gulong i, length;
+
+ /* Show/hide the attachment when the EAttachmentButton
+ * is expanded/collapsed or shown/hidden */
+ g_signal_connect (widget, "notify::expanded",
+ G_CALLBACK (attachment_button_expanded),
+ attachment);
+ g_signal_connect (widget, "notify::visible",
+ G_CALLBACK (attachment_button_expanded),
+ attachment);
+ /* Initial synchronization */
+ attachment_button_expanded (G_OBJECT (widget),
+ NULL, attachment);
+
+ /* Find all <iframes> within the attachment and bind
+ * it's visiblity to expanded state of the attachment btn */
+ nodes = webkit_dom_element_get_elements_by_tag_name (
attachment, "iframe");
+ length = webkit_dom_node_list_get_length (nodes);
+ for (i = 0; i < length; i++) {
- /* 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++) {
+ WebKitDOMNode *node =
+ webkit_dom_node_list_item (nodes, i);
- WebKitDOMElement *child =
- WEBKIT_DOM_ELEMENT (
- webkit_dom_node_list_item (children, i));
-
- if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (child))
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node))
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);
+ bind_iframe_content_visibility (
+ E_ATTACHMENT_BUTTON (widget),
+ WEBKIT_DOM_ELEMENT (node));
}
/* Expand inlined attachments */
@@ -783,6 +922,19 @@ mail_display_plugin_widget_requested (WebKitWebView *web_view,
return widget;
}
+static void
+mail_display_frame_created (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ gpointer user_data)
+{
+ /* Re-bind visibility of this newly created <iframe> with
+ * related EAttachmentButton whenever content of this <iframe> is
+ * (re)loaded */
+
+ g_signal_connect (frame, "notify::load-status",
+ G_CALLBACK (bind_attachment_iframe_visibility), NULL);
+}
+
static void
mail_display_headers_collapsed_state_changed (EWebView *web_view,
@@ -910,6 +1062,8 @@ e_mail_display_init (EMailDisplay *display)
G_CALLBACK (mail_display_webview_update_actions), NULL);
g_signal_connect (display, "create-plugin-widget",
G_CALLBACK (mail_display_plugin_widget_requested), NULL);
+ g_signal_connect (display, "frame-created",
+ G_CALLBACK (mail_display_frame_created), NULL);
/* Because we are loading from a hard-coded string, there is
* no chance of I/O errors. Failure here implies a malformed
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 9c6968e..7f2f0c6 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -965,11 +965,11 @@ efh_write_message_rfc822 (EMFormat *emf,
"background-color: #%06x;\">"
"<div class=\"part-container-inner-margin\">\n"
"<iframe width=\"100%%\" height=\"auto\""
- " frameborder=\"0\" src=\"%s\"></iframe>"
+ " frameborder=\"0\" src=\"%s\" name=\"%s\"></iframe>"
"</div></div>",
e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_FRAME]),
e_color_to_value (&efh->priv->colors[EM_FORMAT_HTML_COLOR_CONTENT]),
- uri);
+ uri, puri->uri);
camel_stream_write_string (stream, str, cancellable, NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]