aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-web-view-gtkhtml.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-web-view-gtkhtml.c')
-rw-r--r--e-util/e-web-view-gtkhtml.c2317
1 files changed, 2317 insertions, 0 deletions
diff --git a/e-util/e-web-view-gtkhtml.c b/e-util/e-web-view-gtkhtml.c
new file mode 100644
index 0000000000..7303277f6a
--- /dev/null
+++ b/e-util/e-web-view-gtkhtml.c
@@ -0,0 +1,2317 @@
+/*
+ * e-web-view-gtkhtml.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-gtkhtml.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+#include <libebackend/libebackend.h>
+
+#include "e-alert-dialog.h"
+#include "e-alert-sink.h"
+#include "e-misc-utils.h"
+#include "e-plugin-ui.h"
+#include "e-popup-action.h"
+#include "e-selectable.h"
+
+#define E_WEB_VIEW_GTKHTML_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_WEB_VIEW_GTKHTML, EWebViewGtkHTMLPrivate))
+
+typedef struct _EWebViewGtkHTMLRequest EWebViewGtkHTMLRequest;
+
+struct _EWebViewGtkHTMLPrivate {
+ GList *requests;
+ GtkUIManager *ui_manager;
+ gchar *selected_uri;
+ GdkPixbufAnimation *cursor_image;
+
+ GtkAction *open_proxy;
+ GtkAction *print_proxy;
+ GtkAction *save_as_proxy;
+
+ GtkTargetList *copy_target_list;
+ GtkTargetList *paste_target_list;
+
+ /* Lockdown Options */
+ guint disable_printing : 1;
+ guint disable_save_to_disk : 1;
+};
+
+struct _EWebViewGtkHTMLRequest {
+ GFile *file;
+ EWebViewGtkHTML *web_view;
+ GCancellable *cancellable;
+ GInputStream *input_stream;
+ GtkHTMLStream *output_stream;
+ gchar buffer[4096];
+};
+
+enum {
+ PROP_0,
+ PROP_ANIMATE,
+ PROP_CARET_MODE,
+ PROP_COPY_TARGET_LIST,
+ PROP_DISABLE_PRINTING,
+ PROP_DISABLE_SAVE_TO_DISK,
+ PROP_EDITABLE,
+ PROP_INLINE_SPELLING,
+ PROP_MAGIC_LINKS,
+ PROP_MAGIC_SMILEYS,
+ PROP_OPEN_PROXY,
+ PROP_PASTE_TARGET_LIST,
+ PROP_PRINT_PROXY,
+ PROP_SAVE_AS_PROXY,
+ PROP_SELECTED_URI,
+ PROP_CURSOR_IMAGE
+};
+
+enum {
+ COPY_CLIPBOARD,
+ CUT_CLIPBOARD,
+ PASTE_CLIPBOARD,
+ 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'/>"
+" </popup>"
+"</ui>";
+
+/* Forward Declarations */
+static void e_web_view_gtkhtml_alert_sink_init (EAlertSinkInterface *interface);
+static void e_web_view_gtkhtml_selectable_init (ESelectableInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+ EWebViewGtkHTML,
+ e_web_view_gtkhtml,
+ GTK_TYPE_HTML,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL)
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_ALERT_SINK,
+ e_web_view_gtkhtml_alert_sink_init)
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_SELECTABLE,
+ e_web_view_gtkhtml_selectable_init))
+
+static EWebViewGtkHTMLRequest *
+web_view_gtkhtml_request_new (EWebViewGtkHTML *web_view,
+ const gchar *uri,
+ GtkHTMLStream *stream)
+{
+ EWebViewGtkHTMLRequest *request;
+ GList *list;
+
+ request = g_slice_new (EWebViewGtkHTMLRequest);
+
+ /* Try to detect file paths posing as URIs. */
+ if (*uri == '/')
+ request->file = g_file_new_for_path (uri);
+ else
+ request->file = g_file_new_for_uri (uri);
+
+ request->web_view = g_object_ref (web_view);
+ request->cancellable = g_cancellable_new ();
+ request->input_stream = NULL;
+ request->output_stream = stream;
+
+ list = request->web_view->priv->requests;
+ list = g_list_prepend (list, request);
+ request->web_view->priv->requests = list;
+
+ return request;
+}
+
+static void
+web_view_gtkhtml_request_free (EWebViewGtkHTMLRequest *request)
+{
+ GList *list;
+
+ list = request->web_view->priv->requests;
+ list = g_list_remove (list, request);
+ request->web_view->priv->requests = list;
+
+ g_object_unref (request->file);
+ g_object_unref (request->web_view);
+ g_object_unref (request->cancellable);
+
+ if (request->input_stream != NULL)
+ g_object_unref (request->input_stream);
+
+ g_slice_free (EWebViewGtkHTMLRequest, request);
+}
+
+static void
+web_view_gtkhtml_request_cancel (EWebViewGtkHTMLRequest *request)
+{
+ g_cancellable_cancel (request->cancellable);
+}
+
+static gboolean
+web_view_gtkhtml_request_check_for_error (EWebViewGtkHTMLRequest *request,
+ GError *error)
+{
+ GtkHTML *html;
+ GtkHTMLStream *stream;
+
+ if (error == NULL)
+ return FALSE;
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
+ /* use this error, but do not close the stream */
+ g_error_free (error);
+ return TRUE;
+ }
+
+ /* XXX Should we log errors that are not cancellations? */
+
+ html = GTK_HTML (request->web_view);
+ stream = request->output_stream;
+
+ gtk_html_end (html, stream, GTK_HTML_STREAM_ERROR);
+ web_view_gtkhtml_request_free (request);
+ g_error_free (error);
+
+ return TRUE;
+}
+
+static void
+web_view_gtkhtml_request_stream_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ EWebViewGtkHTMLRequest *request)
+{
+ gssize bytes_read;
+ GError *error = NULL;
+
+ bytes_read = g_input_stream_read_finish (input_stream, result, &error);
+
+ if (web_view_gtkhtml_request_check_for_error (request, error))
+ return;
+
+ if (bytes_read == 0) {
+ gtk_html_end (
+ GTK_HTML (request->web_view),
+ request->output_stream, GTK_HTML_STREAM_OK);
+ web_view_gtkhtml_request_free (request);
+ return;
+ }
+
+ gtk_html_write (
+ GTK_HTML (request->web_view),
+ request->output_stream, request->buffer, bytes_read);
+
+ g_input_stream_read_async (
+ request->input_stream, request->buffer,
+ sizeof (request->buffer), G_PRIORITY_DEFAULT,
+ request->cancellable, (GAsyncReadyCallback)
+ web_view_gtkhtml_request_stream_read_cb, request);
+}
+
+static void
+web_view_gtkhtml_request_read_cb (GFile *file,
+ GAsyncResult *result,
+ EWebViewGtkHTMLRequest *request)
+{
+ GFileInputStream *input_stream;
+ GError *error = NULL;
+
+ /* Input stream might be NULL, so don't use cast macro. */
+ input_stream = g_file_read_finish (file, result, &error);
+ request->input_stream = (GInputStream *) input_stream;
+
+ if (web_view_gtkhtml_request_check_for_error (request, error))
+ return;
+
+ g_input_stream_read_async (
+ request->input_stream, request->buffer,
+ sizeof (request->buffer), G_PRIORITY_DEFAULT,
+ request->cancellable, (GAsyncReadyCallback)
+ web_view_gtkhtml_request_stream_read_cb, request);
+}
+
+static void
+action_copy_clipboard_cb (GtkAction *action,
+ EWebViewGtkHTML *web_view)
+{
+ e_web_view_gtkhtml_copy_clipboard (web_view);
+}
+
+static void
+action_http_open_cb (GtkAction *action,
+ EWebViewGtkHTML *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_gtkhtml_get_selected_uri (web_view);
+ g_return_if_fail (uri != NULL);
+
+ e_show_uri (parent, uri);
+}
+
+static void
+action_mailto_copy_cb (GtkAction *action,
+ EWebViewGtkHTML *web_view)
+{
+ CamelURL *curl;
+ CamelInternetAddress *inet_addr;
+ GtkClipboard *clipboard;
+ const gchar *uri;
+ gchar *text;
+
+ uri = e_web_view_gtkhtml_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,
+ EWebViewGtkHTML *web_view)
+{
+ e_web_view_gtkhtml_select_all (web_view);
+}
+
+static void
+action_send_message_cb (GtkAction *action,
+ EWebViewGtkHTML *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_gtkhtml_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,
+ EWebViewGtkHTML *web_view)
+{
+ GtkClipboard *clipboard;
+ const gchar *uri;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ uri = e_web_view_gtkhtml_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,
+ EWebViewGtkHTML *web_view)
+{
+ GtkClipboard *clipboard;
+ GdkPixbufAnimation *animation;
+ GdkPixbuf *pixbuf;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ animation = e_web_view_gtkhtml_get_cursor_image (web_view);
+ g_return_if_fail (animation != NULL);
+
+ pixbuf = gdk_pixbuf_animation_get_static_image (animation);
+ if (!pixbuf)
+ 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 gboolean
+web_view_gtkhtml_button_press_event_cb (EWebViewGtkHTML *web_view,
+ GdkEventButton *event,
+ GtkHTML *frame)
+{
+ gboolean event_handled = FALSE;
+ gchar *uri = NULL;
+
+ if (event) {
+ GdkPixbufAnimation *anim;
+
+ if (frame == NULL)
+ frame = GTK_HTML (web_view);
+
+ anim = gtk_html_get_image_at (frame, event->x, event->y);
+ e_web_view_gtkhtml_set_cursor_image (web_view, anim);
+ if (anim != NULL)
+ g_object_unref (anim);
+ }
+
+ if (event != NULL && event->button != 3)
+ return FALSE;
+
+ /* Only extract a URI if no selection is active. Selected text
+ * implies the user is more likely to want to copy the selection
+ * to the clipboard than open a link within the selection. */
+ if (!e_web_view_gtkhtml_is_selection_active (web_view))
+ uri = e_web_view_gtkhtml_extract_uri (web_view, event, frame);
+
+ if (uri != NULL && g_str_has_prefix (uri, "##")) {
+ g_free (uri);
+ return FALSE;
+ }
+
+ g_signal_emit (
+ web_view, signals[POPUP_EVENT], 0,
+ event, uri, &event_handled);
+
+ g_free (uri);
+
+ return event_handled;
+}
+
+static void
+web_view_gtkhtml_menu_item_select_cb (EWebViewGtkHTML *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_gtkhtml_status_message (web_view, tooltip);
+}
+
+static void
+web_view_gtkhtml_menu_item_deselect_cb (EWebViewGtkHTML *web_view)
+{
+ e_web_view_gtkhtml_status_message (web_view, NULL);
+}
+
+static void
+web_view_gtkhtml_connect_proxy_cb (EWebViewGtkHTML *web_view,
+ GtkAction *action,
+ GtkWidget *proxy)
+{
+ if (!GTK_IS_MENU_ITEM (proxy))
+ return;
+
+ g_signal_connect_swapped (
+ proxy, "select",
+ G_CALLBACK (web_view_gtkhtml_menu_item_select_cb), web_view);
+
+ g_signal_connect_swapped (
+ proxy, "deselect",
+ G_CALLBACK (web_view_gtkhtml_menu_item_deselect_cb), web_view);
+}
+
+static void
+web_view_gtkhtml_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE:
+ e_web_view_gtkhtml_set_animate (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_CARET_MODE:
+ e_web_view_gtkhtml_set_caret_mode (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_DISABLE_PRINTING:
+ e_web_view_gtkhtml_set_disable_printing (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_DISABLE_SAVE_TO_DISK:
+ e_web_view_gtkhtml_set_disable_save_to_disk (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_EDITABLE:
+ e_web_view_gtkhtml_set_editable (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_INLINE_SPELLING:
+ e_web_view_gtkhtml_set_inline_spelling (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MAGIC_LINKS:
+ e_web_view_gtkhtml_set_magic_links (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MAGIC_SMILEYS:
+ e_web_view_gtkhtml_set_magic_smileys (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_OPEN_PROXY:
+ e_web_view_gtkhtml_set_open_proxy (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_PRINT_PROXY:
+ e_web_view_gtkhtml_set_print_proxy (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SAVE_AS_PROXY:
+ e_web_view_gtkhtml_set_save_as_proxy (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SELECTED_URI:
+ e_web_view_gtkhtml_set_selected_uri (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_string (value));
+ return;
+ case PROP_CURSOR_IMAGE:
+ e_web_view_gtkhtml_set_cursor_image (
+ E_WEB_VIEW_GTKHTML (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+web_view_gtkhtml_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_animate (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_CARET_MODE:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_caret_mode (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_COPY_TARGET_LIST:
+ g_value_set_boxed (
+ value, e_web_view_gtkhtml_get_copy_target_list (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_DISABLE_PRINTING:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_disable_printing (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_DISABLE_SAVE_TO_DISK:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_disable_save_to_disk (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_EDITABLE:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_editable (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_INLINE_SPELLING:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_inline_spelling (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_MAGIC_LINKS:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_magic_links (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_MAGIC_SMILEYS:
+ g_value_set_boolean (
+ value, e_web_view_gtkhtml_get_magic_smileys (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_OPEN_PROXY:
+ g_value_set_object (
+ value, e_web_view_gtkhtml_get_open_proxy (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_PASTE_TARGET_LIST:
+ g_value_set_boxed (
+ value, e_web_view_gtkhtml_get_paste_target_list (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_PRINT_PROXY:
+ g_value_set_object (
+ value, e_web_view_gtkhtml_get_print_proxy (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_SAVE_AS_PROXY:
+ g_value_set_object (
+ value, e_web_view_gtkhtml_get_save_as_proxy (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_SELECTED_URI:
+ g_value_set_string (
+ value, e_web_view_gtkhtml_get_selected_uri (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+
+ case PROP_CURSOR_IMAGE:
+ g_value_set_object (
+ value, e_web_view_gtkhtml_get_cursor_image (
+ E_WEB_VIEW_GTKHTML (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+web_view_gtkhtml_dispose (GObject *object)
+{
+ EWebViewGtkHTMLPrivate *priv;
+
+ priv = E_WEB_VIEW_GTKHTML_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->copy_target_list != NULL) {
+ gtk_target_list_unref (priv->copy_target_list);
+ priv->copy_target_list = NULL;
+ }
+
+ if (priv->paste_target_list != NULL) {
+ gtk_target_list_unref (priv->paste_target_list);
+ priv->paste_target_list = NULL;
+ }
+
+ if (priv->cursor_image != NULL) {
+ g_object_unref (priv->cursor_image);
+ priv->cursor_image = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_web_view_gtkhtml_parent_class)->dispose (object);
+}
+
+static void
+web_view_gtkhtml_finalize (GObject *object)
+{
+ EWebViewGtkHTMLPrivate *priv;
+
+ priv = E_WEB_VIEW_GTKHTML_GET_PRIVATE (object);
+
+ /* All URI requests should be complete or cancelled by now. */
+ if (priv->requests != NULL)
+ g_warning ("Finalizing EWebViewGtkHTML with active URI requests");
+
+ g_free (priv->selected_uri);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_web_view_gtkhtml_parent_class)->finalize (object);
+}
+
+static void
+web_view_gtkhtml_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
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_web_view_gtkhtml_parent_class)->constructed (object);
+}
+
+static gboolean
+web_view_gtkhtml_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkWidgetClass *widget_class;
+ EWebViewGtkHTML *web_view;
+
+ web_view = E_WEB_VIEW_GTKHTML (widget);
+
+ if (web_view_gtkhtml_button_press_event_cb (web_view, event, NULL))
+ return TRUE;
+
+ /* Chain up to parent's button_press_event() method. */
+ widget_class = GTK_WIDGET_CLASS (e_web_view_gtkhtml_parent_class);
+ return widget_class->button_press_event (widget, event);
+}
+
+static gboolean
+web_view_gtkhtml_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ if (event->state & GDK_CONTROL_MASK) {
+ GdkScrollDirection direction = event->direction;
+
+ #if GTK_CHECK_VERSION(3,3,18)
+ 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;
+ }
+ }
+ #endif
+
+ switch (direction) {
+ case GDK_SCROLL_UP:
+ gtk_html_zoom_in (GTK_HTML (widget));
+ return TRUE;
+ case GDK_SCROLL_DOWN:
+ gtk_html_zoom_out (GTK_HTML (widget));
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+web_view_gtkhtml_url_requested (GtkHTML *html,
+ const gchar *uri,
+ GtkHTMLStream *stream)
+{
+ EWebViewGtkHTMLRequest *request;
+
+ request = web_view_gtkhtml_request_new (E_WEB_VIEW_GTKHTML (html), uri, stream);
+
+ g_file_read_async (
+ request->file, G_PRIORITY_DEFAULT,
+ request->cancellable, (GAsyncReadyCallback)
+ web_view_gtkhtml_request_read_cb, request);
+}
+
+static void
+web_view_gtkhtml_gtkhtml_link_clicked (GtkHTML *html,
+ const gchar *uri)
+{
+ EWebViewGtkHTMLClass *class;
+ EWebViewGtkHTML *web_view;
+
+ web_view = E_WEB_VIEW_GTKHTML (html);
+
+ class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
+ g_return_if_fail (class->link_clicked != NULL);
+
+ class->link_clicked (web_view, uri);
+}
+
+static void
+web_view_gtkhtml_on_url (GtkHTML *html,
+ const gchar *uri)
+{
+ EWebViewGtkHTMLClass *class;
+ EWebViewGtkHTML *web_view;
+
+ web_view = E_WEB_VIEW_GTKHTML (html);
+
+ class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
+ g_return_if_fail (class->hovering_over_link != NULL);
+
+ /* XXX WebKit would supply a title here. */
+ class->hovering_over_link (web_view, NULL, uri);
+}
+
+static void
+web_view_gtkhtml_iframe_created (GtkHTML *html,
+ GtkHTML *iframe)
+{
+ g_signal_connect_swapped (
+ iframe, "button-press-event",
+ G_CALLBACK (web_view_gtkhtml_button_press_event_cb), html);
+}
+
+static gchar *
+web_view_gtkhtml_extract_uri (EWebViewGtkHTML *web_view,
+ GdkEventButton *event,
+ GtkHTML *html)
+{
+ gchar *uri;
+
+ if (event != NULL)
+ uri = gtk_html_get_url_at (html, event->x, event->y);
+ else
+ uri = gtk_html_get_cursor_url (html);
+
+ return uri;
+}
+
+static void
+web_view_gtkhtml_hovering_over_link (EWebViewGtkHTML *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_gtkhtml_status_message (web_view, message);
+
+ g_free (message);
+}
+
+static void
+web_view_gtkhtml_link_clicked (EWebViewGtkHTML *web_view,
+ const gchar *uri)
+{
+ gpointer parent;
+
+ 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_gtkhtml_load_string (EWebViewGtkHTML *web_view,
+ const gchar *string)
+{
+ if (string != NULL && *string != '\0')
+ gtk_html_load_from_string (GTK_HTML (web_view), string, -1);
+ else
+ e_web_view_gtkhtml_clear (web_view);
+}
+
+static void
+web_view_gtkhtml_copy_clipboard (EWebViewGtkHTML *web_view)
+{
+ gtk_html_command (GTK_HTML (web_view), "copy");
+}
+
+static void
+web_view_gtkhtml_cut_clipboard (EWebViewGtkHTML *web_view)
+{
+ if (e_web_view_gtkhtml_get_editable (web_view))
+ gtk_html_command (GTK_HTML (web_view), "cut");
+}
+
+static void
+web_view_gtkhtml_paste_clipboard (EWebViewGtkHTML *web_view)
+{
+ if (e_web_view_gtkhtml_get_editable (web_view))
+ gtk_html_command (GTK_HTML (web_view), "paste");
+}
+
+static gboolean
+web_view_gtkhtml_popup_event (EWebViewGtkHTML *web_view,
+ GdkEventButton *event,
+ const gchar *uri)
+{
+ e_web_view_gtkhtml_set_selected_uri (web_view, uri);
+ e_web_view_gtkhtml_show_popup_menu (web_view, event, NULL, NULL);
+
+ return TRUE;
+}
+
+static void
+web_view_gtkhtml_stop_loading (EWebViewGtkHTML *web_view)
+{
+ g_list_foreach (
+ web_view->priv->requests, (GFunc)
+ web_view_gtkhtml_request_cancel, NULL);
+
+ gtk_html_stop (GTK_HTML (web_view));
+}
+
+static void
+web_view_gtkhtml_update_actions (EWebViewGtkHTML *web_view)
+{
+ GtkActionGroup *action_group;
+ gboolean have_selection;
+ 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_gtkhtml_get_selected_uri (web_view);
+ have_selection = e_web_view_gtkhtml_is_selection_active (web_view);
+ has_cursor_image = e_web_view_gtkhtml_get_cursor_image (web_view) != NULL;
+
+ /* 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_gtkhtml_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_gtkhtml_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_gtkhtml_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_gtkhtml_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+
+ group_name = "selection";
+ visible = have_selection;
+ action_group = e_web_view_gtkhtml_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_gtkhtml_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_gtkhtml_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_gtkhtml_get_action_group (web_view, group_name);
+ gtk_action_group_set_visible (action_group, visible);
+}
+
+static void
+web_view_gtkhtml_submit_alert (EAlertSink *alert_sink,
+ EAlert *alert)
+{
+ GtkIconInfo *icon_info;
+ EWebViewGtkHTML *web_view;
+ GtkWidget *dialog;
+ GString *buffer;
+ const gchar *icon_name = NULL;
+ const gchar *filename;
+ gpointer parent;
+ gchar *icon_uri;
+ gint size = 0;
+ GError *error = NULL;
+
+ web_view = E_WEB_VIEW_GTKHTML (alert_sink);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ /* We use equivalent named icons instead of stock IDs,
+ * since it's easier to get the filename of the icon. */
+ switch (e_alert_get_message_type (alert)) {
+ case GTK_MESSAGE_INFO:
+ icon_name = "dialog-information";
+ break;
+
+ case GTK_MESSAGE_WARNING:
+ icon_name = "dialog-warning";
+ break;
+
+ case GTK_MESSAGE_ERROR:
+ icon_name = "dialog-error";
+ break;
+
+ default:
+ dialog = e_alert_dialog_new (parent, alert);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &size, NULL);
+
+ icon_info = gtk_icon_theme_lookup_icon (
+ gtk_icon_theme_get_default (),
+ icon_name, size, GTK_ICON_LOOKUP_NO_SVG);
+ g_return_if_fail (icon_info != NULL);
+
+ filename = gtk_icon_info_get_filename (icon_info);
+ icon_uri = g_filename_to_uri (filename, NULL, &error);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ 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='%s'/>"
+ "</td>"
+ "<td align='left' width='100%%'>"
+ "<h3>%s</h3>"
+ "%s"
+ "</td>"
+ "</tr>",
+ icon_uri,
+ 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_gtkhtml_load_string (web_view, buffer->str);
+
+ g_string_free (buffer, TRUE);
+
+ gtk_icon_info_free (icon_info);
+ g_free (icon_uri);
+}
+
+static void
+web_view_gtkhtml_selectable_update_actions (ESelectable *selectable,
+ EFocusTracker *focus_tracker,
+ GdkAtom *clipboard_targets,
+ gint n_clipboard_targets)
+{
+ EWebViewGtkHTML *web_view;
+ GtkAction *action;
+ /*GtkTargetList *target_list;*/
+ gboolean can_paste = FALSE;
+ gboolean editable;
+ gboolean have_selection;
+ gboolean sensitive;
+ const gchar *tooltip;
+ /*gint ii;*/
+
+ web_view = E_WEB_VIEW_GTKHTML (selectable);
+ editable = e_web_view_gtkhtml_get_editable (web_view);
+ have_selection = e_web_view_gtkhtml_is_selection_active (web_view);
+
+ /* XXX GtkHtml implements its own clipboard instead of using
+ * GDK_SELECTION_CLIPBOARD, so we don't get notifications
+ * when the clipboard contents change. The logic below
+ * is what we would do if GtkHtml worked properly.
+ * Instead, we need to keep the Paste action sensitive so
+ * its accelerator overrides GtkHtml's key binding. */
+#if 0
+ target_list = e_selectable_get_paste_target_list (selectable);
+ for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++)
+ can_paste = gtk_target_list_find (
+ target_list, clipboard_targets[ii], NULL);
+#endif
+ can_paste = TRUE;
+
+ action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
+ sensitive = editable && have_selection;
+ 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 = have_selection;
+ 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 = editable && can_paste;
+ 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_gtkhtml_selectable_cut_clipboard (ESelectable *selectable)
+{
+ e_web_view_gtkhtml_cut_clipboard (E_WEB_VIEW_GTKHTML (selectable));
+}
+
+static void
+web_view_gtkhtml_selectable_copy_clipboard (ESelectable *selectable)
+{
+ e_web_view_gtkhtml_copy_clipboard (E_WEB_VIEW_GTKHTML (selectable));
+}
+
+static void
+web_view_gtkhtml_selectable_paste_clipboard (ESelectable *selectable)
+{
+ e_web_view_gtkhtml_paste_clipboard (E_WEB_VIEW_GTKHTML (selectable));
+}
+
+static void
+web_view_gtkhtml_selectable_select_all (ESelectable *selectable)
+{
+ e_web_view_gtkhtml_select_all (E_WEB_VIEW_GTKHTML (selectable));
+}
+
+static void
+e_web_view_gtkhtml_class_init (EWebViewGtkHTMLClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkHTMLClass *html_class;
+
+ g_type_class_add_private (class, sizeof (EWebViewGtkHTMLPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = web_view_gtkhtml_set_property;
+ object_class->get_property = web_view_gtkhtml_get_property;
+ object_class->dispose = web_view_gtkhtml_dispose;
+ object_class->finalize = web_view_gtkhtml_finalize;
+ object_class->constructed = web_view_gtkhtml_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->button_press_event = web_view_gtkhtml_button_press_event;
+ widget_class->scroll_event = web_view_gtkhtml_scroll_event;
+
+ html_class = GTK_HTML_CLASS (class);
+ html_class->url_requested = web_view_gtkhtml_url_requested;
+ html_class->link_clicked = web_view_gtkhtml_gtkhtml_link_clicked;
+ html_class->on_url = web_view_gtkhtml_on_url;
+ html_class->iframe_created = web_view_gtkhtml_iframe_created;
+
+ class->extract_uri = web_view_gtkhtml_extract_uri;
+ class->hovering_over_link = web_view_gtkhtml_hovering_over_link;
+ class->link_clicked = web_view_gtkhtml_link_clicked;
+ class->load_string = web_view_gtkhtml_load_string;
+ class->copy_clipboard = web_view_gtkhtml_copy_clipboard;
+ class->cut_clipboard = web_view_gtkhtml_cut_clipboard;
+ class->paste_clipboard = web_view_gtkhtml_paste_clipboard;
+ class->popup_event = web_view_gtkhtml_popup_event;
+ class->stop_loading = web_view_gtkhtml_stop_loading;
+ class->update_actions = web_view_gtkhtml_update_actions;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ANIMATE,
+ g_param_spec_boolean (
+ "animate",
+ "Animate Images",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CARET_MODE,
+ g_param_spec_boolean (
+ "caret-mode",
+ "Caret Mode",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /* Inherited from ESelectableInterface */
+ g_object_class_override_property (
+ object_class,
+ PROP_COPY_TARGET_LIST,
+ "copy-target-list");
+
+ 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_EDITABLE,
+ g_param_spec_boolean (
+ "editable",
+ "Editable",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ 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));
+
+ /* Inherited from ESelectableInterface */
+ g_object_class_override_property (
+ object_class,
+ PROP_PASTE_TARGET_LIST,
+ "paste-target-list");
+
+ 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));
+
+ 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));
+
+ signals[COPY_CLIPBOARD] = g_signal_new (
+ "copy-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewGtkHTMLClass, copy_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[CUT_CLIPBOARD] = g_signal_new (
+ "cut-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewGtkHTMLClass, cut_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[PASTE_CLIPBOARD] = g_signal_new (
+ "paste-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewGtkHTMLClass, paste_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[POPUP_EVENT] = g_signal_new (
+ "popup-event",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewGtkHTMLClass, popup_event),
+ g_signal_accumulator_true_handled, NULL,
+ e_marshal_BOOLEAN__BOXED_STRING,
+ G_TYPE_BOOLEAN, 2,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_STRING);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewGtkHTMLClass, 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 (EWebViewGtkHTMLClass, 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 (EWebViewGtkHTMLClass, 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 (EWebViewGtkHTMLClass, process_mailto),
+ NULL, NULL,
+ e_marshal_BOOLEAN__STRING,
+ G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
+}
+
+static void
+e_web_view_gtkhtml_alert_sink_init (EAlertSinkInterface *interface)
+{
+ interface->submit_alert = web_view_gtkhtml_submit_alert;
+}
+
+static void
+e_web_view_gtkhtml_selectable_init (ESelectableInterface *interface)
+{
+ interface->update_actions = web_view_gtkhtml_selectable_update_actions;
+ interface->cut_clipboard = web_view_gtkhtml_selectable_cut_clipboard;
+ interface->copy_clipboard = web_view_gtkhtml_selectable_copy_clipboard;
+ interface->paste_clipboard = web_view_gtkhtml_selectable_paste_clipboard;
+ interface->select_all = web_view_gtkhtml_selectable_select_all;
+}
+
+static void
+e_web_view_gtkhtml_init (EWebViewGtkHTML *web_view)
+{
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GtkTargetList *target_list;
+ EPopupAction *popup_action;
+ const gchar *domain = GETTEXT_PACKAGE;
+ const gchar *id;
+ GError *error = NULL;
+
+ web_view->priv = E_WEB_VIEW_GTKHTML_GET_PRIVATE (web_view);
+
+ 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_gtkhtml_connect_proxy_cb), web_view);
+
+ target_list = gtk_target_list_new (NULL, 0);
+ web_view->priv->copy_target_list = target_list;
+
+ target_list = gtk_target_list_new (NULL, 0);
+ web_view->priv->paste_target_list = target_list;
+
+ 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);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (web_view));
+}
+
+GtkWidget *
+e_web_view_gtkhtml_new (void)
+{
+ return g_object_new (E_TYPE_WEB_VIEW_GTKHTML, NULL);
+}
+
+void
+e_web_view_gtkhtml_clear (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_load_empty (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_load_string (EWebViewGtkHTML *web_view,
+ const gchar *string)
+{
+ EWebViewGtkHTMLClass *class;
+
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
+ g_return_if_fail (class->load_string != NULL);
+
+ class->load_string (web_view, string);
+}
+
+gboolean
+e_web_view_gtkhtml_get_animate (EWebViewGtkHTML *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_animate(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_get_animate (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_set_animate (EWebViewGtkHTML *web_view,
+ gboolean animate)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_animate()
+ * so we can get a "notify::animate" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_set_animate (GTK_HTML (web_view), animate);
+
+ g_object_notify (G_OBJECT (web_view), "animate");
+}
+
+gboolean
+e_web_view_gtkhtml_get_caret_mode (EWebViewGtkHTML *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_caret_mode(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_get_caret_mode (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_set_caret_mode (EWebViewGtkHTML *web_view,
+ gboolean caret_mode)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_caret_mode()
+ * so we can get a "notify::caret-mode" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_set_caret_mode (GTK_HTML (web_view), caret_mode);
+
+ g_object_notify (G_OBJECT (web_view), "caret-mode");
+}
+
+GtkTargetList *
+e_web_view_gtkhtml_get_copy_target_list (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ return web_view->priv->copy_target_list;
+}
+
+gboolean
+e_web_view_gtkhtml_get_disable_printing (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return web_view->priv->disable_printing;
+}
+
+void
+e_web_view_gtkhtml_set_disable_printing (EWebViewGtkHTML *web_view,
+ gboolean disable_printing)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ web_view->priv->disable_printing = disable_printing;
+
+ g_object_notify (G_OBJECT (web_view), "disable-printing");
+}
+
+gboolean
+e_web_view_gtkhtml_get_disable_save_to_disk (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return web_view->priv->disable_save_to_disk;
+}
+
+void
+e_web_view_gtkhtml_set_disable_save_to_disk (EWebViewGtkHTML *web_view,
+ gboolean disable_save_to_disk)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ 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_gtkhtml_get_editable (EWebViewGtkHTML *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_editable(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_get_editable (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_set_editable (EWebViewGtkHTML *web_view,
+ gboolean editable)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_editable()
+ * so we can get a "notify::editable" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_set_editable (GTK_HTML (web_view), editable);
+
+ g_object_notify (G_OBJECT (web_view), "editable");
+}
+
+gboolean
+e_web_view_gtkhtml_get_inline_spelling (EWebViewGtkHTML *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_inline_spelling(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_get_inline_spelling (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_set_inline_spelling (EWebViewGtkHTML *web_view,
+ gboolean inline_spelling)
+{
+ /* 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_GTKHTML (web_view));
+
+ gtk_html_set_inline_spelling (GTK_HTML (web_view), inline_spelling);
+
+ g_object_notify (G_OBJECT (web_view), "inline-spelling");
+}
+
+gboolean
+e_web_view_gtkhtml_get_magic_links (EWebViewGtkHTML *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_magic_links(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_get_magic_links (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_set_magic_links (EWebViewGtkHTML *web_view,
+ gboolean magic_links)
+{
+ /* 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_GTKHTML (web_view));
+
+ gtk_html_set_magic_links (GTK_HTML (web_view), magic_links);
+
+ g_object_notify (G_OBJECT (web_view), "magic-links");
+}
+
+gboolean
+e_web_view_gtkhtml_get_magic_smileys (EWebViewGtkHTML *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_magic_smileys(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_get_magic_smileys (GTK_HTML (web_view));
+}
+
+void
+e_web_view_gtkhtml_set_magic_smileys (EWebViewGtkHTML *web_view,
+ gboolean magic_smileys)
+{
+ /* 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_GTKHTML (web_view));
+
+ gtk_html_set_magic_smileys (GTK_HTML (web_view), magic_smileys);
+
+ g_object_notify (G_OBJECT (web_view), "magic-smileys");
+}
+
+const gchar *
+e_web_view_gtkhtml_get_selected_uri (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ return web_view->priv->selected_uri;
+}
+
+void
+e_web_view_gtkhtml_set_selected_uri (EWebViewGtkHTML *web_view,
+ const gchar *selected_uri)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ 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_gtkhtml_get_cursor_image (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ return web_view->priv->cursor_image;
+}
+
+void
+e_web_view_gtkhtml_set_cursor_image (EWebViewGtkHTML *web_view,
+ GdkPixbufAnimation *image)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ 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");
+}
+
+GtkAction *
+e_web_view_gtkhtml_get_open_proxy (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return web_view->priv->open_proxy;
+}
+
+void
+e_web_view_gtkhtml_set_open_proxy (EWebViewGtkHTML *web_view,
+ GtkAction *open_proxy)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ 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_gtkhtml_get_paste_target_list (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ return web_view->priv->paste_target_list;
+}
+
+GtkAction *
+e_web_view_gtkhtml_get_print_proxy (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return web_view->priv->print_proxy;
+}
+
+void
+e_web_view_gtkhtml_set_print_proxy (EWebViewGtkHTML *web_view,
+ GtkAction *print_proxy)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ 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_gtkhtml_get_save_as_proxy (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return web_view->priv->save_as_proxy;
+}
+
+void
+e_web_view_gtkhtml_set_save_as_proxy (EWebViewGtkHTML *web_view,
+ GtkAction *save_as_proxy)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ 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");
+}
+
+GtkAction *
+e_web_view_gtkhtml_get_action (EWebViewGtkHTML *web_view,
+ const gchar *action_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ ui_manager = e_web_view_gtkhtml_get_ui_manager (web_view);
+
+ return e_lookup_action (ui_manager, action_name);
+}
+
+GtkActionGroup *
+e_web_view_gtkhtml_get_action_group (EWebViewGtkHTML *web_view,
+ const gchar *group_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+ g_return_val_if_fail (group_name != NULL, NULL);
+
+ ui_manager = e_web_view_gtkhtml_get_ui_manager (web_view);
+
+ return e_lookup_action_group (ui_manager, group_name);
+}
+
+gchar *
+e_web_view_gtkhtml_extract_uri (EWebViewGtkHTML *web_view,
+ GdkEventButton *event,
+ GtkHTML *frame)
+{
+ EWebViewGtkHTMLClass *class;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ if (frame == NULL)
+ frame = GTK_HTML (web_view);
+
+ class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
+ g_return_val_if_fail (class->extract_uri != NULL, NULL);
+
+ return class->extract_uri (web_view, event, frame);
+}
+
+void
+e_web_view_gtkhtml_copy_clipboard (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ g_signal_emit (web_view, signals[COPY_CLIPBOARD], 0);
+}
+
+void
+e_web_view_gtkhtml_cut_clipboard (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ g_signal_emit (web_view, signals[CUT_CLIPBOARD], 0);
+}
+
+gboolean
+e_web_view_gtkhtml_is_selection_active (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_command (GTK_HTML (web_view), "is-selection-active");
+}
+
+void
+e_web_view_gtkhtml_paste_clipboard (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ g_signal_emit (web_view, signals[PASTE_CLIPBOARD], 0);
+}
+
+gboolean
+e_web_view_gtkhtml_scroll_forward (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_command (GTK_HTML (web_view), "scroll-forward");
+}
+
+gboolean
+e_web_view_gtkhtml_scroll_backward (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
+
+ return gtk_html_command (GTK_HTML (web_view), "scroll-backward");
+}
+
+void
+e_web_view_gtkhtml_select_all (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_command (GTK_HTML (web_view), "select-all");
+}
+
+void
+e_web_view_gtkhtml_unselect_all (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_command (GTK_HTML (web_view), "unselect-all");
+}
+
+void
+e_web_view_gtkhtml_zoom_100 (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_command (GTK_HTML (web_view), "zoom-reset");
+}
+
+void
+e_web_view_gtkhtml_zoom_in (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_command (GTK_HTML (web_view), "zoom-in");
+}
+
+void
+e_web_view_gtkhtml_zoom_out (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ gtk_html_command (GTK_HTML (web_view), "zoom-out");
+}
+
+GtkUIManager *
+e_web_view_gtkhtml_get_ui_manager (EWebViewGtkHTML *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ return web_view->priv->ui_manager;
+}
+
+GtkWidget *
+e_web_view_gtkhtml_get_popup_menu (EWebViewGtkHTML *web_view)
+{
+ GtkUIManager *ui_manager;
+ GtkWidget *menu;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
+
+ ui_manager = e_web_view_gtkhtml_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_gtkhtml_show_popup_menu (EWebViewGtkHTML *web_view,
+ GdkEventButton *event,
+ GtkMenuPositionFunc func,
+ gpointer user_data)
+{
+ GtkWidget *menu;
+
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ e_web_view_gtkhtml_update_actions (web_view);
+
+ menu = e_web_view_gtkhtml_get_popup_menu (web_view);
+
+ if (event != NULL)
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, func,
+ user_data, event->button, event->time);
+ else
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, func,
+ user_data, 0, gtk_get_current_event_time ());
+}
+
+void
+e_web_view_gtkhtml_status_message (EWebViewGtkHTML *web_view,
+ const gchar *status_message)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ g_signal_emit (web_view, signals[STATUS_MESSAGE], 0, status_message);
+}
+
+void
+e_web_view_gtkhtml_stop_loading (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ g_signal_emit (web_view, signals[STOP_LOADING], 0);
+}
+
+void
+e_web_view_gtkhtml_update_actions (EWebViewGtkHTML *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
+
+ g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0);
+}