aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-web-view.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-web-view.c')
-rw-r--r--e-util/e-web-view.c2945
1 files changed, 2945 insertions, 0 deletions
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
new file mode 100644
index 0000000000..2fefe4fa95
--- /dev/null
+++ b/e-util/e-web-view.c
@@ -0,0 +1,2945 @@
+/*
+ * e-web-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-web-view.h"
+
+#include <math.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <pango/pango.h>
+
+#include <camel/camel.h>
+#include <libebackend/libebackend.h>
+
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+#include <libsoup/soup.h>
+#include <libsoup/soup-requester.h>
+
+#include "e-alert-dialog.h"
+#include "e-alert-sink.h"
+#include "e-file-request.h"
+#include "e-misc-utils.h"
+#include "e-plugin-ui.h"
+#include "e-popup-action.h"
+#include "e-selectable.h"
+#include "e-stock-request.h"
+
+#define E_WEB_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
+
+typedef struct _EWebViewRequest EWebViewRequest;
+
+struct _EWebViewPrivate {
+ GList *requests;
+ GtkUIManager *ui_manager;
+ gchar *selected_uri;
+ GdkPixbufAnimation *cursor_image;
+ gchar *cursor_image_src;
+
+ GSList *highlights;
+
+ GtkAction *open_proxy;
+ GtkAction *print_proxy;
+ GtkAction *save_as_proxy;
+
+ /* Lockdown Options */
+ guint disable_printing : 1;
+ guint disable_save_to_disk : 1;
+
+ guint caret_mode : 1;
+
+ GSettings *font_settings;
+ GSettings *aliasing_settings;
+};
+
+enum {
+ PROP_0,
+ PROP_CARET_MODE,
+ PROP_COPY_TARGET_LIST,
+ PROP_CURSOR_IMAGE,
+ PROP_CURSOR_IMAGE_SRC,
+ PROP_DISABLE_PRINTING,
+ PROP_DISABLE_SAVE_TO_DISK,
+ PROP_INLINE_SPELLING,
+ PROP_MAGIC_LINKS,
+ PROP_MAGIC_SMILEYS,
+ PROP_OPEN_PROXY,
+ PROP_PRINT_PROXY,
+ PROP_SAVE_AS_PROXY,
+ PROP_SELECTED_URI
+};
+
+enum {
+ POPUP_EVENT,
+ STATUS_MESSAGE,
+ STOP_LOADING,
+ UPDATE_ACTIONS,
+ PROCESS_MAILTO,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static const gchar *ui =
+"<ui>"
+" <popup name='context'>"
+" <menuitem action='copy-clipboard'/>"
+" <separator/>"
+" <placeholder name='custom-actions-1'>"
+" <menuitem action='open'/>"
+" <menuitem action='save-as'/>"
+" <menuitem action='http-open'/>"
+" <menuitem action='send-message'/>"
+" <menuitem action='print'/>"
+" </placeholder>"
+" <placeholder name='custom-actions-2'>"
+" <menuitem action='uri-copy'/>"
+" <menuitem action='mailto-copy'/>"
+" <menuitem action='image-copy'/>"
+" </placeholder>"
+" <placeholder name='custom-actions-3'/>"
+" <separator/>"
+" <menuitem action='select-all'/>"
+" <placeholder name='inspect-menu' />"
+" </popup>"
+"</ui>";
+
+/* Forward Declarations */
+static void e_web_view_alert_sink_init (EAlertSinkInterface *interface);
+static void e_web_view_selectable_init (ESelectableInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+ EWebView,
+ e_web_view,
+ WEBKIT_TYPE_WEB_VIEW,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL)
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_ALERT_SINK,
+ e_web_view_alert_sink_init)
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_SELECTABLE,
+ e_web_view_selectable_init))
+
+static void
+action_copy_clipboard_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ e_web_view_copy_clipboard (web_view);
+}
+
+static void
+action_http_open_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ const gchar *uri;
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ uri = e_web_view_get_selected_uri (web_view);
+ g_return_if_fail (uri != NULL);
+
+ e_show_uri (parent, uri);
+}
+
+static void
+action_mailto_copy_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ CamelURL *curl;
+ CamelInternetAddress *inet_addr;
+ GtkClipboard *clipboard;
+ const gchar *uri;
+ gchar *text;
+
+ uri = e_web_view_get_selected_uri (web_view);
+ g_return_if_fail (uri != NULL);
+
+ /* This should work because we checked it in update_actions(). */
+ curl = camel_url_new (uri, NULL);
+ g_return_if_fail (curl != NULL);
+
+ inet_addr = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path);
+ text = camel_address_format (CAMEL_ADDRESS (inet_addr));
+ if (text == NULL || *text == '\0')
+ text = g_strdup (uri + strlen ("mailto:"));
+
+ g_object_unref (inet_addr);
+ camel_url_free (curl);
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+ gtk_clipboard_set_text (clipboard, text, -1);
+ gtk_clipboard_store (clipboard);
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clipboard, text, -1);
+ gtk_clipboard_store (clipboard);
+
+ g_free (text);
+}
+
+static void
+action_select_all_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ e_web_view_select_all (web_view);
+}
+
+static void
+action_send_message_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ const gchar *uri;
+ gpointer parent;
+ gboolean handled;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ uri = e_web_view_get_selected_uri (web_view);
+ g_return_if_fail (uri != NULL);
+
+ handled = FALSE;
+ g_signal_emit (web_view, signals[PROCESS_MAILTO], 0, uri, &handled);
+
+ if (!handled)
+ e_show_uri (parent, uri);
+}
+
+static void
+action_uri_copy_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ GtkClipboard *clipboard;
+ const gchar *uri;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ uri = e_web_view_get_selected_uri (web_view);
+ g_return_if_fail (uri != NULL);
+
+ gtk_clipboard_set_text (clipboard, uri, -1);
+ gtk_clipboard_store (clipboard);
+}
+
+static void
+action_image_copy_cb (GtkAction *action,
+ EWebView *web_view)
+{
+ GtkClipboard *clipboard;
+ GdkPixbufAnimation *animation;
+ GdkPixbuf *pixbuf;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ animation = e_web_view_get_cursor_image (web_view);
+ g_return_if_fail (animation != NULL);
+
+ pixbuf = gdk_pixbuf_animation_get_static_image (animation);
+ if (pixbuf == NULL)
+ return;
+
+ gtk_clipboard_set_image (clipboard, pixbuf);
+ gtk_clipboard_store (clipboard);
+}
+
+static GtkActionEntry uri_entries[] = {
+
+ { "uri-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy Link Location"),
+ NULL,
+ N_("Copy the link to the clipboard"),
+ G_CALLBACK (action_uri_copy_cb) }
+};
+
+static GtkActionEntry http_entries[] = {
+
+ { "http-open",
+ "emblem-web",
+ N_("_Open Link in Browser"),
+ NULL,
+ N_("Open the link in a web browser"),
+ G_CALLBACK (action_http_open_cb) }
+};
+
+static GtkActionEntry mailto_entries[] = {
+
+ { "mailto-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy Email Address"),
+ NULL,
+ N_("Copy the email address to the clipboard"),
+ G_CALLBACK (action_mailto_copy_cb) },
+
+ { "send-message",
+ "mail-message-new",
+ N_("_Send New Message To..."),
+ NULL,
+ N_("Send a mail message to this address"),
+ G_CALLBACK (action_send_message_cb) }
+};
+
+static GtkActionEntry image_entries[] = {
+
+ { "image-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy Image"),
+ NULL,
+ N_("Copy the image to the clipboard"),
+ G_CALLBACK (action_image_copy_cb) }
+};
+
+static GtkActionEntry selection_entries[] = {
+
+ { "copy-clipboard",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy the selection"),
+ G_CALLBACK (action_copy_clipboard_cb) },
+};
+
+static GtkActionEntry standard_entries[] = {
+
+ { "select-all",
+ GTK_STOCK_SELECT_ALL,
+ NULL,
+ NULL,
+ N_("Select all text and images"),
+ G_CALLBACK (action_select_all_cb) }
+};
+
+static void
+web_view_menu_item_select_cb (EWebView *web_view,
+ GtkWidget *widget)
+{
+ GtkAction *action;
+ GtkActivatable *activatable;
+ const gchar *tooltip;
+
+ activatable = GTK_ACTIVATABLE (widget);
+ action = gtk_activatable_get_related_action (activatable);
+ tooltip = gtk_action_get_tooltip (action);
+
+ if (tooltip == NULL)
+ return;
+
+ e_web_view_status_message (web_view, tooltip);
+}
+
+static void
+replace_text (WebKitDOMNode *node,
+ const gchar *text,
+ WebKitDOMNode *replacement)
+{
+ /* NodeType 3 = TEXT_NODE */
+ if (webkit_dom_node_get_node_type (node) == 3) {
+ gint text_length = strlen (text);
+
+ while (node) {
+
+ WebKitDOMNode *current_node, *replacement_node;
+ const gchar *node_data, *offset;
+ goffset split_offset;
+ gint data_length;
+
+ current_node = node;
+
+ /* Don't use the WEBKIT_DOM_CHARACTER_DATA macro for
+ * casting. WebKit lies about type of the object and
+ * GLib will throw runtime warning about node not being
+ * WebKitDOMCharacterData, but the function will return
+ * correct and valid data.
+ * IMO it's bug in the Gtk bindings and WebKit internally
+ * handles it by the nodeType so therefor it works
+ * event for "invalid" objects. But really, who knows..?
+ */
+ node_data = webkit_dom_character_data_get_data (
+ (WebKitDOMCharacterData *) node);
+
+ offset = strstr (node_data, text);
+ if (offset == NULL) {
+ node = NULL;
+ continue;
+ }
+
+ split_offset = offset - node_data + text_length;
+ replacement_node =
+ webkit_dom_node_clone_node (replacement, TRUE);
+
+ data_length = webkit_dom_character_data_get_length (
+ (WebKitDOMCharacterData *) node);
+ if (split_offset < data_length) {
+
+ WebKitDOMNode *parent_node;
+
+ node = WEBKIT_DOM_NODE (
+ webkit_dom_text_split_text (
+ (WebKitDOMText *) node,
+ offset - node_data + text_length,
+ NULL));
+ parent_node = webkit_dom_node_get_parent_node (node);
+ webkit_dom_node_insert_before (
+ parent_node, replacement_node,
+ node, NULL);
+
+ } else {
+ WebKitDOMNode *parent_node;
+
+ parent_node = webkit_dom_node_get_parent_node (node);
+ webkit_dom_node_append_child (
+ parent_node,
+ replacement_node, NULL);
+ }
+
+ webkit_dom_character_data_delete_data (
+ (WebKitDOMCharacterData *) (current_node),
+ offset - node_data, text_length, NULL);
+ }
+
+ } else {
+ WebKitDOMNode *child, *next_child;
+
+ /* Iframe? Let's traverse inside! */
+ if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) {
+
+ WebKitDOMDocument *frame_document;
+
+ frame_document =
+ webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+ replace_text (
+ WEBKIT_DOM_NODE (frame_document),
+ text, replacement);
+
+ } else {
+ child = webkit_dom_node_get_first_child (node);
+ while (child != NULL) {
+ next_child = webkit_dom_node_get_next_sibling (child);
+ replace_text (child, text, replacement);
+ child = next_child;
+ }
+ }
+ }
+}
+
+static void
+web_view_update_document_highlights (EWebView *web_view)
+{
+ WebKitDOMDocument *document;
+ GSList *iter;
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
+
+ for (iter = web_view->priv->highlights; iter; iter = iter->next) {
+
+ WebKitDOMDocumentFragment *frag;
+ WebKitDOMElement *span;
+
+ span = webkit_dom_document_create_element (document, "span", NULL);
+
+ /* See https://bugzilla.gnome.org/show_bug.cgi?id=681400
+ * FIXME: This can be removed once we require WebKitGtk 1.10+ */
+ #if WEBKIT_CHECK_VERSION (1, 9, 6)
+ webkit_dom_element_set_class_name (
+ span, "__evo-highlight");
+ #else
+ webkit_dom_html_element_set_class_name (
+ WEBKIT_DOM_HTML_ELEMENT (span), "__evo-highlight");
+ #endif
+
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (span), iter->data, NULL);
+
+ frag = webkit_dom_document_create_document_fragment (document);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (frag), WEBKIT_DOM_NODE (span), NULL);
+
+ replace_text (
+ WEBKIT_DOM_NODE (document),
+ iter->data, WEBKIT_DOM_NODE (frag));
+ }
+}
+
+static void
+web_view_menu_item_deselect_cb (EWebView *web_view)
+{
+ e_web_view_status_message (web_view, NULL);
+}
+
+static void
+web_view_connect_proxy_cb (EWebView *web_view,
+ GtkAction *action,
+ GtkWidget *proxy)
+{
+ if (!GTK_IS_MENU_ITEM (proxy))
+ return;
+
+ g_signal_connect_swapped (
+ proxy, "select",
+ G_CALLBACK (web_view_menu_item_select_cb), web_view);
+
+ g_signal_connect_swapped (
+ proxy, "deselect",
+ G_CALLBACK (web_view_menu_item_deselect_cb), web_view);
+}
+
+static GtkWidget *
+web_view_create_plugin_widget_cb (EWebView *web_view,
+ const gchar *mime_type,
+ const gchar *uri,
+ GHashTable *param)
+{
+ EWebViewClass *class;
+
+ /* XXX WebKitWebView does not provide a class method for
+ * this signal, so we do so we can override the default
+ * behavior from subclasses for special URI types. */
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_val_if_fail (class->create_plugin_widget != NULL, NULL);
+
+ return class->create_plugin_widget (web_view, mime_type, uri, param);
+}
+
+static void
+web_view_hovering_over_link_cb (EWebView *web_view,
+ const gchar *title,
+ const gchar *uri)
+{
+ EWebViewClass *class;
+
+ /* XXX WebKitWebView does not provide a class method for
+ * this signal, so we do so we can override the default
+ * behavior from subclasses for special URI types. */
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_if_fail (class->hovering_over_link != NULL);
+
+ class->hovering_over_link (web_view, title, uri);
+}
+
+static gboolean
+web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision)
+{
+ EWebViewClass *class;
+ WebKitWebNavigationReason reason;
+ const gchar *uri;
+
+ reason = webkit_web_navigation_action_get_reason (navigation_action);
+ if (reason != WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
+ return FALSE;
+
+ /* XXX WebKitWebView does not provide a class method for
+ * this signal, so we do so we can override the default
+ * behavior from subclasses for special URI types. */
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_val_if_fail (class->link_clicked != NULL, FALSE);
+
+ webkit_web_policy_decision_ignore (policy_decision);
+
+ uri = webkit_network_request_get_uri (request);
+
+ class->link_clicked (web_view, uri);
+
+ return TRUE;
+}
+
+static void
+web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ WebKitLoadStatus status;
+ EWebView *web_view;
+
+ status = webkit_web_view_get_load_status (webkit_web_view);
+ if (status != WEBKIT_LOAD_FINISHED)
+ return;
+
+ web_view = E_WEB_VIEW (webkit_web_view);
+ web_view_update_document_highlights (web_view);
+
+ /* Workaround webkit bug https://bugs.webkit.org/show_bug.cgi?id=89553 */
+ e_web_view_zoom_in (web_view);
+ e_web_view_zoom_out (web_view);
+}
+
+static void
+web_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CARET_MODE:
+ e_web_view_set_caret_mode (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_CURSOR_IMAGE:
+ e_web_view_set_cursor_image (
+ E_WEB_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_CURSOR_IMAGE_SRC:
+ e_web_view_set_cursor_image_src (
+ E_WEB_VIEW (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_DISABLE_PRINTING:
+ e_web_view_set_disable_printing (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_DISABLE_SAVE_TO_DISK:
+ e_web_view_set_disable_save_to_disk (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_INLINE_SPELLING:
+ e_web_view_set_inline_spelling (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MAGIC_LINKS:
+ e_web_view_set_magic_links (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MAGIC_SMILEYS:
+ e_web_view_set_magic_smileys (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_OPEN_PROXY:
+ e_web_view_set_open_proxy (
+ E_WEB_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_PRINT_PROXY:
+ e_web_view_set_print_proxy (
+ E_WEB_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SAVE_AS_PROXY:
+ e_web_view_set_save_as_proxy (
+ E_WEB_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SELECTED_URI:
+ e_web_view_set_selected_uri (
+ E_WEB_VIEW (object),
+ g_value_get_string (value));
+ return;
+ }
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+web_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CARET_MODE:
+ g_value_set_boolean (
+ value, e_web_view_get_caret_mode (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_CURSOR_IMAGE:
+ g_value_set_object (
+ value, e_web_view_get_cursor_image (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_CURSOR_IMAGE_SRC:
+ g_value_set_string (
+ value, e_web_view_get_cursor_image_src (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_DISABLE_PRINTING:
+ g_value_set_boolean (
+ value, e_web_view_get_disable_printing (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_DISABLE_SAVE_TO_DISK:
+ g_value_set_boolean (
+ value, e_web_view_get_disable_save_to_disk (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_INLINE_SPELLING:
+ g_value_set_boolean (
+ value, e_web_view_get_inline_spelling (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_MAGIC_LINKS:
+ g_value_set_boolean (
+ value, e_web_view_get_magic_links (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_MAGIC_SMILEYS:
+ g_value_set_boolean (
+ value, e_web_view_get_magic_smileys (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_OPEN_PROXY:
+ g_value_set_object (
+ value, e_web_view_get_open_proxy (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_PRINT_PROXY:
+ g_value_set_object (
+ value, e_web_view_get_print_proxy (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_SAVE_AS_PROXY:
+ g_value_set_object (
+ value, e_web_view_get_save_as_proxy (
+ E_WEB_VIEW (object)));
+ return;
+
+ case PROP_SELECTED_URI:
+ g_value_set_string (
+ value, e_web_view_get_selected_uri (
+ E_WEB_VIEW (object)));
+ return;
+
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+web_view_dispose (GObject *object)
+{
+ EWebViewPrivate *priv;
+
+ priv = E_WEB_VIEW_GET_PRIVATE (object);
+
+ if (priv->ui_manager != NULL) {
+ g_object_unref (priv->ui_manager);
+ priv->ui_manager = NULL;
+ }
+
+ if (priv->open_proxy != NULL) {
+ g_object_unref (priv->open_proxy);
+ priv->open_proxy = NULL;
+ }
+
+ if (priv->print_proxy != NULL) {
+ g_object_unref (priv->print_proxy);
+ priv->print_proxy = NULL;
+ }
+
+ if (priv->save_as_proxy != NULL) {
+ g_object_unref (priv->save_as_proxy);
+ priv->save_as_proxy = NULL;
+ }
+
+ if (priv->cursor_image != NULL) {
+ g_object_unref (priv->cursor_image);
+ priv->cursor_image = NULL;
+ }
+
+ if (priv->cursor_image_src != NULL) {
+ g_free (priv->cursor_image_src);
+ priv->cursor_image_src = NULL;
+ }
+
+ if (priv->highlights != NULL) {
+ g_slist_free_full (priv->highlights, g_free);
+ priv->highlights = NULL;
+ }
+
+ if (priv->aliasing_settings != NULL) {
+ g_signal_handlers_disconnect_matched (
+ priv->aliasing_settings, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, object);
+ g_object_unref (priv->aliasing_settings);
+ priv->aliasing_settings = NULL;
+ }
+
+ if (priv->font_settings != NULL) {
+ g_signal_handlers_disconnect_matched (
+ priv->font_settings, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, object);
+ g_object_unref (priv->font_settings);
+ priv->font_settings = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_web_view_parent_class)->dispose (object);
+}
+
+static void
+web_view_finalize (GObject *object)
+{
+ EWebViewPrivate *priv;
+
+ priv = E_WEB_VIEW_GET_PRIVATE (object);
+
+ /* All URI requests should be complete or cancelled by now. */
+ if (priv->requests != NULL)
+ g_warning ("Finalizing EWebView with active URI requests");
+
+ g_free (priv->selected_uri);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
+}
+
+static void
+web_view_constructed (GObject *object)
+{
+#ifndef G_OS_WIN32
+ GSettings *settings;
+
+ settings = g_settings_new ("org.gnome.desktop.lockdown");
+
+ g_settings_bind (
+ settings, "disable-printing",
+ object, "disable-printing",
+ G_SETTINGS_BIND_GET);
+
+ g_settings_bind (
+ settings, "disable-save-to-disk",
+ object, "disable-save-to-disk",
+ G_SETTINGS_BIND_GET);
+
+ g_object_unref (settings);
+#endif
+
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_web_view_parent_class)->constructed (object);
+}
+
+static gboolean
+web_view_context_menu_cb (WebKitWebView *webkit_web_view,
+ GtkWidget *default_menu,
+ WebKitHitTestResult *hit_test_result,
+ gboolean triggered_with_keyboard)
+{
+ WebKitHitTestResultContext context;
+ EWebView *web_view;
+ gboolean event_handled = FALSE;
+ gchar *uri;
+
+ web_view = E_WEB_VIEW (webkit_web_view);
+
+ if (web_view->priv->cursor_image != NULL) {
+ g_object_unref (web_view->priv->cursor_image);
+ web_view->priv->cursor_image = NULL;
+ }
+
+ if (web_view->priv->cursor_image_src != NULL) {
+ g_free (web_view->priv->cursor_image_src);
+ web_view->priv->cursor_image_src = NULL;
+ }
+
+ if (hit_test_result == NULL)
+ return FALSE;
+
+ g_object_get (G_OBJECT (hit_test_result), "context", &context, NULL);
+
+ if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
+ WebKitWebDataSource *data_source;
+ WebKitWebFrame *frame;
+ GList *subresources, *res;
+
+ g_object_get (
+ G_OBJECT (hit_test_result), "image-uri", &uri, NULL);
+
+ if (uri == NULL)
+ return FALSE;
+
+ g_free (web_view->priv->cursor_image_src);
+ web_view->priv->cursor_image_src = uri;
+
+ /* Iterate through all resources of the loaded webpage and
+ * try to find resource with URI matching cursor_image_src */
+ frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ data_source = webkit_web_frame_get_data_source (frame);
+ subresources = webkit_web_data_source_get_subresources (data_source);
+ for (res = subresources; res; res = res->next) {
+ WebKitWebResource *src = res->data;
+ GdkPixbufLoader *loader;
+ GString *data;
+
+ if (g_strcmp0 (webkit_web_resource_get_uri (src),
+ web_view->priv->cursor_image_src) != 0)
+ continue;
+
+ data = webkit_web_resource_get_data (src);
+ if (data == NULL)
+ break;
+
+ loader = gdk_pixbuf_loader_new ();
+ if (!gdk_pixbuf_loader_write (loader,
+ (guchar *) data->str, data->len, NULL)) {
+ g_object_unref (loader);
+ break;
+ }
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ if (web_view->priv->cursor_image != NULL)
+ g_object_unref (web_view->priv->cursor_image);
+
+ web_view->priv->cursor_image =
+ g_object_ref (gdk_pixbuf_loader_get_animation (loader));
+
+ g_object_unref (loader);
+ break;
+ }
+ g_list_free (subresources);
+ }
+
+ g_object_get (hit_test_result, "link-uri", &uri, NULL);
+
+ if (!(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)) {
+ g_free (uri);
+ uri = NULL;
+ }
+
+ g_signal_emit (web_view, signals[POPUP_EVENT], 0, uri, &event_handled);
+
+ g_free (uri);
+
+ return event_handled;
+}
+
+static gboolean
+web_view_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ if (event->state & GDK_CONTROL_MASK) {
+ GdkScrollDirection direction = event->direction;
+
+ if (direction == GDK_SCROLL_SMOOTH) {
+ static gdouble total_delta_y = 0.0;
+
+ total_delta_y += event->delta_y;
+
+ if (total_delta_y >= 1.0) {
+ total_delta_y = 0.0;
+ direction = GDK_SCROLL_DOWN;
+ } else if (total_delta_y <= -1.0) {
+ total_delta_y = 0.0;
+ direction = GDK_SCROLL_UP;
+ } else {
+ return FALSE;
+ }
+ }
+
+ switch (direction) {
+ case GDK_SCROLL_UP:
+ e_web_view_zoom_in (E_WEB_VIEW (widget));
+ return TRUE;
+ case GDK_SCROLL_DOWN:
+ e_web_view_zoom_out (E_WEB_VIEW (widget));
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static GtkWidget *
+web_view_create_plugin_widget (EWebView *web_view,
+ const gchar *mime_type,
+ const gchar *uri,
+ GHashTable *param)
+{
+ GtkWidget *widget = NULL;
+
+ if (g_strcmp0 (mime_type, "image/x-themed-icon") == 0) {
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf;
+ gpointer data;
+ glong size = 0;
+ GError *error = NULL;
+
+ icon_theme = gtk_icon_theme_get_default ();
+
+ if (size == 0) {
+ data = g_hash_table_lookup (param, "width");
+ if (data != NULL)
+ size = MAX (size, strtol (data, NULL, 10));
+ }
+
+ if (size == 0) {
+ data = g_hash_table_lookup (param, "height");
+ if (data != NULL)
+ size = MAX (size, strtol (data, NULL, 10));
+ }
+
+ if (size == 0)
+ size = 32; /* arbitrary default */
+
+ pixbuf = gtk_icon_theme_load_icon (
+ icon_theme, uri, size, 0, &error);
+ if (pixbuf != NULL) {
+ widget = gtk_image_new_from_pixbuf (pixbuf);
+ g_object_unref (pixbuf);
+ } else if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ }
+
+ return widget;
+}
+
+static gchar *
+web_view_extract_uri (EWebView *web_view,
+ GdkEventButton *event)
+{
+ WebKitHitTestResult *result;
+ WebKitHitTestResultContext context;
+ gchar *uri = NULL;
+
+ result = webkit_web_view_get_hit_test_result (
+ WEBKIT_WEB_VIEW (web_view), event);
+
+ g_object_get (result, "context", &context, "link-uri", &uri, NULL);
+ g_object_unref (result);
+
+ if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+ return uri;
+
+ g_free (uri);
+
+ return NULL;
+}
+
+static void
+web_view_hovering_over_link (EWebView *web_view,
+ const gchar *title,
+ const gchar *uri)
+{
+ CamelInternetAddress *address;
+ CamelURL *curl;
+ const gchar *format = NULL;
+ gchar *message = NULL;
+ gchar *who;
+
+ if (uri == NULL || *uri == '\0')
+ goto exit;
+
+ if (g_str_has_prefix (uri, "mailto:"))
+ format = _("Click to mail %s");
+ else if (g_str_has_prefix (uri, "callto:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "h323:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "sip:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "##"))
+ message = g_strdup (_("Click to hide/unhide addresses"));
+ else
+ message = g_strdup_printf (_("Click to open %s"), uri);
+
+ if (format == NULL)
+ goto exit;
+
+ /* XXX Use something other than Camel here. Surely
+ * there's other APIs around that can do this. */
+ curl = camel_url_new (uri, NULL);
+ address = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (address), curl->path);
+ who = camel_address_format (CAMEL_ADDRESS (address));
+ g_object_unref (address);
+ camel_url_free (curl);
+
+ if (who == NULL)
+ who = g_strdup (strchr (uri, ':') + 1);
+
+ message = g_strdup_printf (format, who);
+
+ g_free (who);
+
+exit:
+ e_web_view_status_message (web_view, message);
+
+ g_free (message);
+}
+
+static void
+web_view_link_clicked (EWebView *web_view,
+ const gchar *uri)
+{
+ gpointer parent;
+
+ if (uri && g_ascii_strncasecmp (uri, "mailto:", 7) == 0) {
+ gboolean handled = FALSE;
+
+ g_signal_emit (
+ web_view, signals[PROCESS_MAILTO], 0, uri, &handled);
+
+ if (handled)
+ return;
+ }
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ e_show_uri (parent, uri);
+}
+
+static void
+web_view_load_string (EWebView *web_view,
+ const gchar *string)
+{
+ if (string == NULL)
+ string = "";
+
+ webkit_web_view_load_string (
+ WEBKIT_WEB_VIEW (web_view),
+ string, "text/html", "UTF-8", "evo-file:///");
+}
+
+static void
+web_view_load_uri (EWebView *web_view,
+ const gchar *uri)
+{
+ if (uri == NULL)
+ uri = "about:blank";
+
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), uri);
+}
+
+static void
+web_view_frame_load_string (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *string)
+{
+ WebKitWebFrame *main_frame;
+
+ if (string == NULL)
+ string = "";
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ if (main_frame != NULL) {
+ WebKitWebFrame *frame;
+
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ if (frame != NULL)
+ webkit_web_frame_load_string (
+ frame, string, "text/html",
+ "UTF-8", "evo-file:///");
+ }
+}
+
+static void
+web_view_frame_load_uri (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *uri)
+{
+ WebKitWebFrame *main_frame;
+
+ if (uri == NULL)
+ uri = "about:blank";
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ if (main_frame != NULL) {
+ WebKitWebFrame *frame;
+
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ if (frame != NULL)
+ webkit_web_frame_load_uri (frame, uri);
+ }
+}
+
+static gboolean
+web_view_popup_event (EWebView *web_view,
+ const gchar *uri)
+{
+ e_web_view_set_selected_uri (web_view, uri);
+ e_web_view_show_popup_menu (web_view);
+
+ return TRUE;
+}
+
+static void
+web_view_stop_loading (EWebView *web_view)
+{
+ webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
+}
+
+static void
+web_view_update_actions (EWebView *web_view)
+{
+ GtkActionGroup *action_group;
+ gboolean can_copy;
+ gboolean scheme_is_http = FALSE;
+ gboolean scheme_is_mailto = FALSE;
+ gboolean uri_is_valid = FALSE;
+ gboolean has_cursor_image;
+ gboolean visible;
+ const gchar *group_name;
+ const gchar *uri;
+
+ uri = e_web_view_get_selected_uri (web_view);
+ can_copy = webkit_web_view_can_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
+ has_cursor_image = e_web_view_get_cursor_image_src (web_view) ||
+ e_web_view_get_cursor_image (web_view);
+
+ /* Parse the URI early so we know if the actions will work. */
+ if (uri != NULL) {
+ CamelURL *curl;
+
+ curl = camel_url_new (uri, NULL);
+ uri_is_valid = (curl != NULL);
+ camel_url_free (curl);
+
+ scheme_is_http =
+ (g_ascii_strncasecmp (uri, "http:", 5) == 0) ||
+ (g_ascii_strncasecmp (uri, "https:", 6) == 0);
+
+ scheme_is_mailto =
+ (g_ascii_strncasecmp (uri, "mailto:", 7) == 0);
+ }
+
+ /* Allow copying the URI even if it's malformed. */
+ group_name = "uri";
+ visible = (uri != NULL) && !scheme_is_mailto;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "http";
+ visible = uri_is_valid && scheme_is_http;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "mailto";
+ visible = uri_is_valid && scheme_is_mailto;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "image";
+ visible = has_cursor_image;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "selection";
+ visible = can_copy;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "standard";
+ visible = (uri == NULL);
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "lockdown-printing";
+ visible = (uri == NULL) && !web_view->priv->disable_printing;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "lockdown-save-to-disk";
+ visible = (uri == NULL) && !web_view->priv->disable_save_to_disk;
+ action_group = e_web_view_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+}
+
+static void
+web_view_submit_alert (EAlertSink *alert_sink,
+ EAlert *alert)
+{
+ EWebView *web_view;
+ GtkWidget *dialog;
+ GString *buffer;
+ const gchar *icon_name = NULL;
+ gpointer parent;
+
+ web_view = E_WEB_VIEW (alert_sink);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ switch (e_alert_get_message_type (alert)) {
+ case GTK_MESSAGE_INFO:
+ icon_name = GTK_STOCK_DIALOG_INFO;
+ break;
+
+ case GTK_MESSAGE_WARNING:
+ icon_name = GTK_STOCK_DIALOG_WARNING;
+ break;
+
+ case GTK_MESSAGE_ERROR:
+ icon_name = GTK_STOCK_DIALOG_ERROR;
+ break;
+
+ default:
+ dialog = e_alert_dialog_new (parent, alert);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
+ buffer = g_string_sized_new (512);
+
+ g_string_append (
+ buffer,
+ "<html>"
+ "<head>"
+ "<meta http-equiv=\"content-type\""
+ " content=\"text/html; charset=utf-8\">"
+ "</head>"
+ "<body>");
+
+ g_string_append (
+ buffer,
+ "<table bgcolor='#000000' width='100%'"
+ " cellpadding='1' cellspacing='0'>"
+ "<tr>"
+ "<td>"
+ "<table bgcolor='#dddddd' width='100%' cellpadding='6'>"
+ "<tr>");
+
+ g_string_append_printf (
+ buffer,
+ "<tr>"
+ "<td valign='top'>"
+ "<img src='gtk-stock://%s/?size=%d'/>"
+ "</td>"
+ "<td align='left' width='100%%'>"
+ "<h3>%s</h3>"
+ "%s"
+ "</td>"
+ "</tr>",
+ icon_name,
+ GTK_ICON_SIZE_DIALOG,
+ e_alert_get_primary_text (alert),
+ e_alert_get_secondary_text (alert));
+
+ g_string_append (
+ buffer,
+ "</table>"
+ "</td>"
+ "</tr>"
+ "</table>"
+ "</body>"
+ "</html>");
+
+ e_web_view_load_string (web_view, buffer->str);
+
+ g_string_free (buffer, TRUE);
+}
+
+static void
+web_view_selectable_update_actions (ESelectable *selectable,
+ EFocusTracker *focus_tracker,
+ GdkAtom *clipboard_targets,
+ gint n_clipboard_targets)
+{
+ WebKitWebView *web_view;
+ GtkAction *action;
+ gboolean sensitive;
+ const gchar *tooltip;
+
+ web_view = WEBKIT_WEB_VIEW (selectable);
+
+ action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
+ sensitive = webkit_web_view_can_cut_clipboard (web_view);
+ tooltip = _("Cut the selection");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
+
+ action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
+ sensitive = webkit_web_view_can_copy_clipboard (web_view);
+ tooltip = _("Copy the selection");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
+
+ action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
+ sensitive = webkit_web_view_can_paste_clipboard (web_view);
+ tooltip = _("Paste the clipboard");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
+
+ action = e_focus_tracker_get_select_all_action (focus_tracker);
+ sensitive = TRUE;
+ tooltip = _("Select all text and images");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
+}
+
+static void
+web_view_selectable_cut_clipboard (ESelectable *selectable)
+{
+ e_web_view_cut_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
+web_view_selectable_copy_clipboard (ESelectable *selectable)
+{
+ e_web_view_copy_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
+web_view_selectable_paste_clipboard (ESelectable *selectable)
+{
+ e_web_view_paste_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
+web_view_selectable_select_all (ESelectable *selectable)
+{
+ e_web_view_select_all (E_WEB_VIEW (selectable));
+}
+
+static gboolean
+web_view_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_)
+{
+ return FALSE;
+}
+
+static void
+e_web_view_class_init (EWebViewClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ g_type_class_add_private (class, sizeof (EWebViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = web_view_set_property;
+ object_class->get_property = web_view_get_property;
+ object_class->dispose = web_view_dispose;
+ object_class->finalize = web_view_finalize;
+ object_class->constructed = web_view_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->scroll_event = web_view_scroll_event;
+ widget_class->drag_motion = web_view_drag_motion;
+
+#if 0 /* WEBKIT */
+ html_class = GTK_HTML_CLASS (class);
+ html_class->url_requested = web_view_url_requested;
+#endif
+
+ class->create_plugin_widget = web_view_create_plugin_widget;
+ class->extract_uri = web_view_extract_uri;
+ class->hovering_over_link = web_view_hovering_over_link;
+ class->link_clicked = web_view_link_clicked;
+ class->load_string = web_view_load_string;
+ class->load_uri = web_view_load_uri;
+ class->frame_load_string = web_view_frame_load_string;
+ class->frame_load_uri = web_view_frame_load_uri;
+ class->popup_event = web_view_popup_event;
+ class->stop_loading = web_view_stop_loading;
+ class->update_actions = web_view_update_actions;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CARET_MODE,
+ g_param_spec_boolean (
+ "caret-mode",
+ "Caret Mode",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURSOR_IMAGE,
+ g_param_spec_object (
+ "cursor-image",
+ "Image animation at the mouse cursor",
+ NULL,
+ GDK_TYPE_PIXBUF_ANIMATION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURSOR_IMAGE_SRC,
+ g_param_spec_string (
+ "cursor-image-src",
+ "Image source uri at the mouse cursor",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DISABLE_PRINTING,
+ g_param_spec_boolean (
+ "disable-printing",
+ "Disable Printing",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DISABLE_SAVE_TO_DISK,
+ g_param_spec_boolean (
+ "disable-save-to-disk",
+ "Disable Save-to-Disk",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_INLINE_SPELLING,
+ g_param_spec_boolean (
+ "inline-spelling",
+ "Inline Spelling",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MAGIC_LINKS,
+ g_param_spec_boolean (
+ "magic-links",
+ "Magic Links",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MAGIC_SMILEYS,
+ g_param_spec_boolean (
+ "magic-smileys",
+ "Magic Smileys",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_OPEN_PROXY,
+ g_param_spec_object (
+ "open-proxy",
+ "Open Proxy",
+ NULL,
+ GTK_TYPE_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PRINT_PROXY,
+ g_param_spec_object (
+ "print-proxy",
+ "Print Proxy",
+ NULL,
+ GTK_TYPE_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SAVE_AS_PROXY,
+ g_param_spec_object (
+ "save-as-proxy",
+ "Save As Proxy",
+ NULL,
+ GTK_TYPE_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTED_URI,
+ g_param_spec_string (
+ "selected-uri",
+ "Selected URI",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ signals[POPUP_EVENT] = g_signal_new (
+ "popup-event",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, popup_event),
+ g_signal_accumulator_true_handled, NULL,
+ e_marshal_BOOLEAN__STRING,
+ G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, status_message),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+
+ signals[STOP_LOADING] = g_signal_new (
+ "stop-loading",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, stop_loading),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[UPDATE_ACTIONS] = g_signal_new (
+ "update-actions",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, update_actions),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /* return TRUE when a signal handler processed the mailto URI */
+ signals[PROCESS_MAILTO] = g_signal_new (
+ "process-mailto",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, process_mailto),
+ NULL, NULL,
+ e_marshal_BOOLEAN__STRING,
+ G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
+}
+
+static void
+e_web_view_alert_sink_init (EAlertSinkInterface *interface)
+{
+ interface->submit_alert = web_view_submit_alert;
+}
+
+static void
+e_web_view_selectable_init (ESelectableInterface *interface)
+{
+ interface->update_actions = web_view_selectable_update_actions;
+ interface->cut_clipboard = web_view_selectable_cut_clipboard;
+ interface->copy_clipboard = web_view_selectable_copy_clipboard;
+ interface->paste_clipboard = web_view_selectable_paste_clipboard;
+ interface->select_all = web_view_selectable_select_all;
+}
+
+static void
+e_web_view_init (EWebView *web_view)
+{
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ EPopupAction *popup_action;
+ WebKitWebSettings *web_settings;
+ GSettingsSchema *settings_schema;
+ GSettings *settings;
+ const gchar *domain = GETTEXT_PACKAGE;
+ const gchar *id;
+ GError *error = NULL;
+
+ web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
+
+ web_view->priv->highlights = NULL;
+
+ g_signal_connect (
+ web_view, "create-plugin-widget",
+ G_CALLBACK (web_view_create_plugin_widget_cb), NULL);
+
+ g_signal_connect (
+ web_view, "hovering-over-link",
+ G_CALLBACK (web_view_hovering_over_link_cb), NULL);
+
+ g_signal_connect (
+ web_view, "navigation-policy-decision-requested",
+ G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
+ NULL);
+
+ g_signal_connect (
+ web_view, "new-window-policy-decision-requested",
+ G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
+ NULL);
+
+ g_signal_connect (
+ web_view, "context-menu",
+ G_CALLBACK (web_view_context_menu_cb), NULL);
+
+ g_signal_connect (
+ web_view, "notify::load-status",
+ G_CALLBACK (web_view_load_status_changed_cb), NULL);
+
+ ui_manager = gtk_ui_manager_new ();
+ web_view->priv->ui_manager = ui_manager;
+
+ g_signal_connect_swapped (
+ ui_manager, "connect-proxy",
+ G_CALLBACK (web_view_connect_proxy_cb), web_view);
+
+ web_settings = e_web_view_get_default_settings ();
+ e_web_view_set_settings (web_view, web_settings);
+ g_object_unref (web_settings);
+
+ e_web_view_install_request_handler (web_view, E_TYPE_FILE_REQUEST);
+ e_web_view_install_request_handler (web_view, E_TYPE_STOCK_REQUEST);
+
+ settings = g_settings_new ("org.gnome.desktop.interface");
+ g_signal_connect_swapped (
+ settings, "changed::font-name",
+ G_CALLBACK (e_web_view_update_fonts), web_view);
+ g_signal_connect_swapped (
+ settings, "changed::monospace-font-name",
+ G_CALLBACK (e_web_view_update_fonts), web_view);
+ web_view->priv->font_settings = settings;
+
+ /* This schema is optional. Use if available. */
+ id = "org.gnome.settings-daemon.plugins.xsettings";
+ settings_schema = g_settings_schema_source_lookup (
+ g_settings_schema_source_get_default (), id, FALSE);
+ if (settings_schema != NULL) {
+ settings = g_settings_new (id);
+ g_signal_connect_swapped (
+ settings, "changed::antialiasing",
+ G_CALLBACK (e_web_view_update_fonts), web_view);
+ web_view->priv->aliasing_settings = settings;
+ }
+
+ e_web_view_update_fonts (web_view);
+
+ action_group = gtk_action_group_new ("uri");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ gtk_action_group_add_actions (
+ action_group, uri_entries,
+ G_N_ELEMENTS (uri_entries), web_view);
+
+ action_group = gtk_action_group_new ("http");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ gtk_action_group_add_actions (
+ action_group, http_entries,
+ G_N_ELEMENTS (http_entries), web_view);
+
+ action_group = gtk_action_group_new ("mailto");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ gtk_action_group_add_actions (
+ action_group, mailto_entries,
+ G_N_ELEMENTS (mailto_entries), web_view);
+
+ action_group = gtk_action_group_new ("image");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ gtk_action_group_add_actions (
+ action_group, image_entries,
+ G_N_ELEMENTS (image_entries), web_view);
+
+ action_group = gtk_action_group_new ("selection");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ gtk_action_group_add_actions (
+ action_group, selection_entries,
+ G_N_ELEMENTS (selection_entries), web_view);
+
+ action_group = gtk_action_group_new ("standard");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ gtk_action_group_add_actions (
+ action_group, standard_entries,
+ G_N_ELEMENTS (standard_entries), web_view);
+
+ popup_action = e_popup_action_new ("open");
+ gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
+ g_object_unref (popup_action);
+
+ g_object_bind_property (
+ web_view, "open-proxy",
+ popup_action, "related-action",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ /* Support lockdown. */
+
+ action_group = gtk_action_group_new ("lockdown-printing");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ popup_action = e_popup_action_new ("print");
+ gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
+ g_object_unref (popup_action);
+
+ g_object_bind_property (
+ web_view, "print-proxy",
+ popup_action, "related-action",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ action_group = gtk_action_group_new ("lockdown-save-to-disk");
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ popup_action = e_popup_action_new ("save-as");
+ gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
+ g_object_unref (popup_action);
+
+ g_object_bind_property (
+ web_view, "save-as-proxy",
+ popup_action, "related-action",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ /* Because we are loading from a hard-coded string, there is
+ * no chance of I/O errors. Failure here implies a malformed
+ * UI definition. Full stop. */
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+ if (error != NULL)
+ g_error ("%s", error->message);
+
+ id = "org.gnome.evolution.webview";
+ e_plugin_ui_register_manager (ui_manager, id, web_view);
+ e_plugin_ui_enable_manager (ui_manager, id);
+}
+
+GtkWidget *
+e_web_view_new (void)
+{
+ return g_object_new (E_TYPE_WEB_VIEW, NULL);
+}
+
+void
+e_web_view_clear (EWebView *web_view)
+{
+ GtkStyle *style;
+ gchar *html;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ style = gtk_widget_get_style (GTK_WIDGET (web_view));
+
+ html = g_strdup_printf (
+ "<html><head></head><body bgcolor=\"#%06x\"></body></html>",
+ e_color_to_value (&style->base[GTK_STATE_NORMAL]));
+
+ webkit_web_view_load_html_string (
+ WEBKIT_WEB_VIEW (web_view), html, NULL);
+
+ g_free (html);
+}
+
+void
+e_web_view_load_string (EWebView *web_view,
+ const gchar *string)
+{
+ EWebViewClass *class;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_if_fail (class->load_string != NULL);
+
+ class->load_string (web_view, string);
+}
+
+void
+e_web_view_load_uri (EWebView *web_view,
+ const gchar *uri)
+{
+ EWebViewClass *class;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_if_fail (class->load_uri != NULL);
+
+ class->load_uri (web_view, uri);
+}
+
+void
+e_web_view_reload (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
+}
+
+const gchar *
+e_web_view_get_uri (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return webkit_web_view_get_uri (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_frame_load_string (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *string)
+{
+ EWebViewClass *class;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (frame_name != NULL);
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_if_fail (class->frame_load_string != NULL);
+
+ class->frame_load_string (web_view, frame_name, string);
+}
+
+void
+e_web_view_frame_load_uri (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *uri)
+{
+ EWebViewClass *class;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (frame_name != NULL);
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_if_fail (class->frame_load_uri != NULL);
+
+ class->frame_load_uri (web_view, frame_name, uri);
+}
+
+const gchar *
+e_web_view_frame_get_uri (EWebView *web_view,
+ const gchar *frame_name)
+{
+ WebKitWebFrame *main_frame;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+ g_return_val_if_fail (frame_name != NULL, NULL);
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ if (main_frame != NULL) {
+ WebKitWebFrame *frame;
+
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ if (frame != NULL)
+ return webkit_web_frame_get_uri (frame);
+ }
+
+ return NULL;
+}
+
+gchar *
+e_web_view_get_html (EWebView *web_view)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
+ element = webkit_dom_document_get_document_element (document);
+
+ return webkit_dom_html_element_get_outer_html (
+ WEBKIT_DOM_HTML_ELEMENT (element));
+}
+
+gboolean
+e_web_view_get_caret_mode (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return web_view->priv->caret_mode;
+}
+
+void
+e_web_view_set_caret_mode (EWebView *web_view,
+ gboolean caret_mode)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->caret_mode == caret_mode)
+ return;
+
+ web_view->priv->caret_mode = caret_mode;
+
+ g_object_notify (G_OBJECT (web_view), "caret-mode");
+}
+
+GtkTargetList *
+e_web_view_get_copy_target_list (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return webkit_web_view_get_copy_target_list (
+ WEBKIT_WEB_VIEW (web_view));
+}
+
+gboolean
+e_web_view_get_disable_printing (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return web_view->priv->disable_printing;
+}
+
+void
+e_web_view_set_disable_printing (EWebView *web_view,
+ gboolean disable_printing)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->disable_printing == disable_printing)
+ return;
+
+ web_view->priv->disable_printing = disable_printing;
+
+ g_object_notify (G_OBJECT (web_view), "disable-printing");
+}
+
+gboolean
+e_web_view_get_disable_save_to_disk (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return web_view->priv->disable_save_to_disk;
+}
+
+void
+e_web_view_set_disable_save_to_disk (EWebView *web_view,
+ gboolean disable_save_to_disk)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->disable_save_to_disk == disable_save_to_disk)
+ return;
+
+ web_view->priv->disable_save_to_disk = disable_save_to_disk;
+
+ g_object_notify (G_OBJECT (web_view), "disable-save-to-disk");
+}
+
+gboolean
+e_web_view_get_enable_frame_flattening (EWebView *web_view)
+{
+ WebKitWebSettings *settings;
+ gboolean flattening;
+
+ /* Return TRUE with fail since it's default value we set in _init(). */
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), TRUE);
+
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
+ g_return_val_if_fail (settings != NULL, TRUE);
+
+ g_object_get (
+ G_OBJECT (settings),
+ "enable-frame-flattening", &flattening, NULL);
+
+ return flattening;
+}
+
+void
+e_web_view_set_enable_frame_flattening (EWebView *web_view,
+ gboolean enable_frame_flattening)
+{
+ WebKitWebSettings *settings;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
+ g_return_if_fail (settings != NULL);
+
+ g_object_set (
+ G_OBJECT (settings), "enable-frame-flattening",
+ enable_frame_flattening, NULL);
+}
+
+gboolean
+e_web_view_get_editable (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return webkit_web_view_get_editable (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_set_editable (EWebView *web_view,
+ gboolean editable)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view), editable);
+}
+
+gboolean
+e_web_view_get_inline_spelling (EWebView *web_view)
+{
+#if 0 /* WEBKIT - XXX No equivalent property? */
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_inline_spelling(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return gtk_html_get_inline_spelling (GTK_HTML (web_view));
+#endif
+
+ return FALSE;
+}
+
+void
+e_web_view_set_inline_spelling (EWebView *web_view,
+ gboolean inline_spelling)
+{
+#if 0 /* WEBKIT - XXX No equivalent property? */
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_inline_spelling()
+ * so we get a "notify::inline-spelling" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ gtk_html_set_inline_spelling (GTK_HTML (web_view), inline_spelling);
+
+ g_object_notify (G_OBJECT (web_view), "inline-spelling");
+#endif
+}
+
+gboolean
+e_web_view_get_magic_links (EWebView *web_view)
+{
+#if 0 /* WEBKIT - XXX No equivalent property? */
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_magic_links(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return gtk_html_get_magic_links (GTK_HTML (web_view));
+#endif
+
+ return FALSE;
+}
+
+void
+e_web_view_set_magic_links (EWebView *web_view,
+ gboolean magic_links)
+{
+#if 0 /* WEBKIT - XXX No equivalent property? */
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_magic_links()
+ * so we can get a "notify::magic-links" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ gtk_html_set_magic_links (GTK_HTML (web_view), magic_links);
+
+ g_object_notify (G_OBJECT (web_view), "magic-links");
+#endif
+}
+
+gboolean
+e_web_view_get_magic_smileys (EWebView *web_view)
+{
+#if 0 /* WEBKIT - No equivalent property? */
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_magic_smileys(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return gtk_html_get_magic_smileys (GTK_HTML (web_view));
+#endif
+
+ return FALSE;
+}
+
+void
+e_web_view_set_magic_smileys (EWebView *web_view,
+ gboolean magic_smileys)
+{
+#if 0 /* WEBKIT - No equivalent property? */
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_magic_smileys()
+ * so we can get a "notify::magic-smileys" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ gtk_html_set_magic_smileys (GTK_HTML (web_view), magic_smileys);
+
+ g_object_notify (G_OBJECT (web_view), "magic-smileys");
+#endif
+}
+
+const gchar *
+e_web_view_get_selected_uri (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->selected_uri;
+}
+
+void
+e_web_view_set_selected_uri (EWebView *web_view,
+ const gchar *selected_uri)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (g_strcmp0 (web_view->priv->selected_uri, selected_uri) == 0)
+ return;
+
+ g_free (web_view->priv->selected_uri);
+ web_view->priv->selected_uri = g_strdup (selected_uri);
+
+ g_object_notify (G_OBJECT (web_view), "selected-uri");
+}
+
+GdkPixbufAnimation *
+e_web_view_get_cursor_image (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->cursor_image;
+}
+
+void
+e_web_view_set_cursor_image (EWebView *web_view,
+ GdkPixbufAnimation *image)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->cursor_image == image)
+ return;
+
+ if (image != NULL)
+ g_object_ref (image);
+
+ if (web_view->priv->cursor_image != NULL)
+ g_object_unref (web_view->priv->cursor_image);
+
+ web_view->priv->cursor_image = image;
+
+ g_object_notify (G_OBJECT (web_view), "cursor-image");
+}
+
+const gchar *
+e_web_view_get_cursor_image_src (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->cursor_image_src;
+}
+
+void
+e_web_view_set_cursor_image_src (EWebView *web_view,
+ const gchar *src_uri)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (g_strcmp0 (web_view->priv->cursor_image_src, src_uri) == 0)
+ return;
+
+ g_free (web_view->priv->cursor_image_src);
+ web_view->priv->cursor_image_src = g_strdup (src_uri);
+
+ g_object_notify (G_OBJECT (web_view), "cursor-image-src");
+}
+
+GtkAction *
+e_web_view_get_open_proxy (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return web_view->priv->open_proxy;
+}
+
+void
+e_web_view_set_open_proxy (EWebView *web_view,
+ GtkAction *open_proxy)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->open_proxy == open_proxy)
+ return;
+
+ if (open_proxy != NULL) {
+ g_return_if_fail (GTK_IS_ACTION (open_proxy));
+ g_object_ref (open_proxy);
+ }
+
+ if (web_view->priv->open_proxy != NULL)
+ g_object_unref (web_view->priv->open_proxy);
+
+ web_view->priv->open_proxy = open_proxy;
+
+ g_object_notify (G_OBJECT (web_view), "open-proxy");
+}
+
+GtkTargetList *
+e_web_view_get_paste_target_list (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return webkit_web_view_get_paste_target_list (
+ WEBKIT_WEB_VIEW (web_view));
+}
+
+GtkAction *
+e_web_view_get_print_proxy (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return web_view->priv->print_proxy;
+}
+
+void
+e_web_view_set_print_proxy (EWebView *web_view,
+ GtkAction *print_proxy)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->print_proxy == print_proxy)
+ return;
+
+ if (print_proxy != NULL) {
+ g_return_if_fail (GTK_IS_ACTION (print_proxy));
+ g_object_ref (print_proxy);
+ }
+
+ if (web_view->priv->print_proxy != NULL)
+ g_object_unref (web_view->priv->print_proxy);
+
+ web_view->priv->print_proxy = print_proxy;
+
+ g_object_notify (G_OBJECT (web_view), "print-proxy");
+}
+
+GtkAction *
+e_web_view_get_save_as_proxy (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return web_view->priv->save_as_proxy;
+}
+
+void
+e_web_view_set_save_as_proxy (EWebView *web_view,
+ GtkAction *save_as_proxy)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (web_view->priv->save_as_proxy == save_as_proxy)
+ return;
+
+ if (save_as_proxy != NULL) {
+ g_return_if_fail (GTK_IS_ACTION (save_as_proxy));
+ g_object_ref (save_as_proxy);
+ }
+
+ if (web_view->priv->save_as_proxy != NULL)
+ g_object_unref (web_view->priv->save_as_proxy);
+
+ web_view->priv->save_as_proxy = save_as_proxy;
+
+ g_object_notify (G_OBJECT (web_view), "save-as-proxy");
+}
+
+GSList *
+e_web_view_get_highlights (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->highlights;
+}
+
+void
+e_web_view_add_highlight (EWebView *web_view,
+ const gchar *highlight)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (highlight && *highlight);
+
+ web_view->priv->highlights = g_slist_append (
+ web_view->priv->highlights, g_strdup (highlight));
+
+ web_view_update_document_highlights (web_view);
+}
+
+void e_web_view_clear_highlights (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (!web_view->priv->highlights)
+ return;
+
+ g_slist_free_full (web_view->priv->highlights, g_free);
+ web_view->priv->highlights = NULL;
+
+ web_view_update_document_highlights (web_view);
+}
+
+GtkAction *
+e_web_view_get_action (EWebView *web_view,
+ const gchar *action_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ ui_manager = e_web_view_get_ui_manager (web_view);
+
+ return e_lookup_action (ui_manager, action_name);
+}
+
+GtkActionGroup *
+e_web_view_get_action_group (EWebView *web_view,
+ const gchar *group_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+ g_return_val_if_fail (group_name != NULL, NULL);
+
+ ui_manager = e_web_view_get_ui_manager (web_view);
+
+ return e_lookup_action_group (ui_manager, group_name);
+}
+
+gchar *
+e_web_view_extract_uri (EWebView *web_view,
+ GdkEventButton *event)
+{
+ EWebViewClass *class;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ g_return_val_if_fail (class->extract_uri != NULL, NULL);
+
+ return class->extract_uri (web_view, event);
+}
+
+void
+e_web_view_copy_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_cut_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_cut_clipboard (WEBKIT_WEB_VIEW (web_view));
+}
+
+gboolean
+e_web_view_is_selection_active (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_paste_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_paste_clipboard (WEBKIT_WEB_VIEW (web_view));
+}
+
+gboolean
+e_web_view_scroll_forward (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ webkit_web_view_move_cursor (
+ WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, 1);
+
+ return TRUE; /* XXX This means nothing. */
+}
+
+gboolean
+e_web_view_scroll_backward (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ webkit_web_view_move_cursor (
+ WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, -1);
+
+ return TRUE; /* XXX This means nothing. */
+}
+
+void
+e_web_view_select_all (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_select_all (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_unselect_all (EWebView *web_view)
+{
+#if 0 /* WEBKIT */
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ gtk_html_command (GTK_HTML (web_view), "unselect-all");
+#endif
+}
+
+void
+e_web_view_zoom_100 (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0);
+}
+
+void
+e_web_view_zoom_in (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
+}
+
+void
+e_web_view_zoom_out (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
+}
+
+GtkUIManager *
+e_web_view_get_ui_manager (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->ui_manager;
+}
+
+GtkWidget *
+e_web_view_get_popup_menu (EWebView *web_view)
+{
+ GtkUIManager *ui_manager;
+ GtkWidget *menu;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ ui_manager = e_web_view_get_ui_manager (web_view);
+ menu = gtk_ui_manager_get_widget (ui_manager, "/context");
+ g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
+
+ return menu;
+}
+
+void
+e_web_view_show_popup_menu (EWebView *web_view)
+{
+ GtkWidget *menu;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ e_web_view_update_actions (web_view);
+
+ menu = e_web_view_get_popup_menu (web_view);
+
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, NULL, NULL,
+ 0, gtk_get_current_event_time ());
+}
+
+void
+e_web_view_status_message (EWebView *web_view,
+ const gchar *status_message)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[STATUS_MESSAGE], 0, status_message);
+}
+
+void
+e_web_view_stop_loading (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[STOP_LOADING], 0);
+}
+
+void
+e_web_view_update_actions (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0);
+}
+
+static gchar *
+web_view_get_frame_selection_html (WebKitDOMElement *iframe)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *window;
+ WebKitDOMDOMSelection *selection;
+ WebKitDOMNodeList *frames;
+ gulong ii, length;
+
+ document = webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+ window = webkit_dom_document_get_default_view (document);
+ selection = webkit_dom_dom_window_get_selection (window);
+ if (selection && (webkit_dom_dom_selection_get_range_count (selection) > 0)) {
+ WebKitDOMRange *range;
+ WebKitDOMElement *element;
+ WebKitDOMDocumentFragment *fragment;
+
+ range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
+ if (range != NULL) {
+ fragment = webkit_dom_range_clone_contents (
+ range, NULL);
+
+ element = webkit_dom_document_create_element (
+ document, "DIV", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (fragment), NULL);
+
+ return webkit_dom_html_element_get_inner_html (
+ WEBKIT_DOM_HTML_ELEMENT (element));
+ }
+ }
+
+ 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++) {
+ WebKitDOMNode *node;
+ gchar *text;
+
+ node = webkit_dom_node_list_item (frames, ii);
+
+ text = web_view_get_frame_selection_html (
+ WEBKIT_DOM_ELEMENT (node));
+
+ if (text != NULL)
+ return text;
+ }
+
+ return NULL;
+}
+
+gchar *
+e_web_view_get_selection_html (EWebView *web_view)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *frames;
+ gulong ii, length;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ if (!webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view)))
+ return NULL;
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
+ 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++) {
+ gchar *text;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (frames, ii);
+
+ text = web_view_get_frame_selection_html (
+ WEBKIT_DOM_ELEMENT (node));
+
+ if (text != NULL)
+ return text;
+ }
+
+ return NULL;
+}
+
+void
+e_web_view_set_settings (EWebView *web_view,
+ WebKitWebSettings *settings)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (settings == webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view)))
+ return;
+
+ g_object_bind_property (
+ settings, "enable-caret-browsing",
+ web_view, "caret-mode",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ webkit_web_view_set_settings (WEBKIT_WEB_VIEW (web_view), settings);
+}
+
+WebKitWebSettings *
+e_web_view_get_default_settings (void)
+{
+ WebKitWebSettings *settings;
+
+ settings = webkit_web_settings_new ();
+
+ g_object_set (
+ G_OBJECT (settings),
+ "enable-frame-flattening", TRUE,
+ "enable-java-applet", FALSE,
+ "enable-html5-database", FALSE,
+ "enable-html5-local-storage", FALSE,
+ "enable-offline-web-application-cache", FALSE,
+ "enable-site-specific-quirks", TRUE,
+ "enable-scripts", FALSE,
+ NULL);
+
+ return settings;
+}
+
+void
+e_web_view_update_fonts (EWebView *web_view)
+{
+ EWebViewClass *class;
+ GString *stylesheet;
+ gchar *base64;
+ gchar *aa = NULL;
+ WebKitWebSettings *settings;
+ PangoFontDescription *min_size, *ms, *vw;
+ const gchar *styles[] = { "normal", "oblique", "italic" };
+ const gchar *smoothing = NULL;
+ GtkStyleContext *context;
+ GdkColor *link = NULL;
+ GdkColor *visited = NULL;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ ms = NULL;
+ vw = NULL;
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ if (class->set_fonts != NULL)
+ class->set_fonts (web_view, &ms, &vw);
+
+ if (ms == NULL) {
+ gchar *font;
+
+ font = g_settings_get_string (
+ web_view->priv->font_settings,
+ "monospace-font-name");
+
+ ms = pango_font_description_from_string (
+ (font != NULL) ? font : "monospace 10");
+
+ g_free (font);
+ }
+
+ if (vw == NULL) {
+ gchar *font;
+
+ font = g_settings_get_string (
+ web_view->priv->font_settings,
+ "font-name");
+
+ vw = pango_font_description_from_string (
+ (font != NULL) ? font : "serif 10");
+
+ g_free (font);
+ }
+
+ if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw)) {
+ min_size = ms;
+ } else {
+ min_size = vw;
+ }
+
+ stylesheet = g_string_new ("");
+ g_string_append_printf (
+ stylesheet,
+ "body {\n"
+ " font-family: '%s';\n"
+ " font-size: %dpt;\n"
+ " font-weight: %d;\n"
+ " font-style: %s;\n",
+ pango_font_description_get_family (vw),
+ pango_font_description_get_size (vw) / PANGO_SCALE,
+ pango_font_description_get_weight (vw),
+ styles[pango_font_description_get_style (vw)]);
+
+ if (web_view->priv->aliasing_settings != NULL)
+ aa = g_settings_get_string (
+ web_view->priv->aliasing_settings, "antialiasing");
+
+ if (g_strcmp0 (aa, "none") == 0)
+ smoothing = "none";
+ else if (g_strcmp0 (aa, "grayscale") == 0)
+ smoothing = "antialiased";
+ else if (g_strcmp0 (aa, "rgba") == 0)
+ smoothing = "subpixel-antialiased";
+
+ if (smoothing != NULL)
+ g_string_append_printf (
+ stylesheet,
+ " -webkit-font-smoothing: %s;\n",
+ smoothing);
+
+ g_free (aa);
+
+ g_string_append (stylesheet, "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "pre,code,.pre {\n"
+ " font-family: '%s';\n"
+ " font-size: %dpt;\n"
+ " font-weight: %d;\n"
+ " font-style: %s;\n"
+ "}",
+ pango_font_description_get_family (ms),
+ pango_font_description_get_size (ms) / PANGO_SCALE,
+ pango_font_description_get_weight (ms),
+ styles[pango_font_description_get_style (ms)]);
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
+ gtk_style_context_get_style (
+ context,
+ "link-color", &link,
+ "visited-link-color", &visited,
+ NULL);
+
+ if (link == NULL) {
+ link = g_slice_new0 (GdkColor);
+ link->blue = G_MAXINT16;
+ }
+
+ if (visited == NULL) {
+ visited = g_slice_new0 (GdkColor);
+ visited->red = G_MAXINT16;
+ }
+
+ g_string_append_printf (
+ stylesheet,
+ "a {\n"
+ " color: #%06x;\n"
+ "}\n"
+ "a:visited {\n"
+ " color: #%06x;\n"
+ "}\n",
+ e_color_to_value (link),
+ e_color_to_value (visited));
+
+ gdk_color_free (link);
+ gdk_color_free (visited);
+
+ base64 = g_base64_encode ((guchar *) stylesheet->str, stylesheet->len);
+ g_string_free (stylesheet, TRUE);
+
+ stylesheet = g_string_new ("data:text/css;charset=utf-8;base64,");
+ g_string_append (stylesheet, base64);
+ g_free (base64);
+
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
+ g_object_set (
+ G_OBJECT (settings),
+ "default-font-size", pango_font_description_get_size (vw) / PANGO_SCALE,
+ "default-font-family", pango_font_description_get_family (vw),
+ "monospace-font-family", pango_font_description_get_family (ms),
+ "default-monospace-font-size", (pango_font_description_get_size (ms) / PANGO_SCALE),
+ "minimum-font-size", (pango_font_description_get_size (min_size) / PANGO_SCALE),
+ "user-stylesheet-uri", stylesheet->str,
+ NULL);
+
+ g_string_free (stylesheet, TRUE);
+
+ pango_font_description_free (ms);
+ pango_font_description_free (vw);
+}
+
+void
+e_web_view_install_request_handler (EWebView *web_view,
+ GType handler_type)
+{
+ SoupSession *session;
+ SoupSessionFeature *feature;
+ gboolean new;
+
+ session = webkit_get_default_session ();
+
+ feature = soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
+ new = FALSE;
+ if (feature == NULL) {
+ feature = SOUP_SESSION_FEATURE (soup_requester_new ());
+ soup_session_add_feature (session, feature);
+ new = TRUE;
+ }
+
+ soup_session_feature_add_feature (feature, handler_type);
+
+ if (new) {
+ g_object_unref (feature);
+ }
+}
+