aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc/e-web-view.c
diff options
context:
space:
mode:
authorDan Vrátil <dvratil@redhat.com>2012-03-29 00:37:35 +0800
committerDan Vrátil <dvratil@redhat.com>2012-03-29 00:37:35 +0800
commit6bd1c6833a2c51898ac45865767dd01ba66a95c5 (patch)
tree51f9cc360c49e71c455f74f72f1605965e73a932 /widgets/misc/e-web-view.c
parent038e0eccec595ce1cc39fe95262272e29d5a6fbf (diff)
downloadgsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.tar
gsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.tar.gz
gsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.tar.bz2
gsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.tar.lz
gsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.tar.xz
gsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.tar.zst
gsoc2013-evolution-6bd1c6833a2c51898ac45865767dd01ba66a95c5.zip
WebKit port - port widgets
Diffstat (limited to 'widgets/misc/e-web-view.c')
-rw-r--r--widgets/misc/e-web-view.c1402
1 files changed, 934 insertions, 468 deletions
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 26c922470b..1fdc5559d9 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -22,6 +22,10 @@
#include "e-web-view.h"
+#include <math.h>
+
+#include <JavaScriptCore/JavaScript.h>
+
#include <string.h>
#include <glib/gi18n-lib.h>
@@ -33,8 +37,11 @@
#include <libevolution-utils/e-alert-sink.h>
#include <e-util/e-plugin-ui.h>
+#include <mail/e-mail-request.h>
+
#include "e-popup-action.h"
#include "e-selectable.h"
+#include <stdlib.h>
#define E_WEB_VIEW_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -49,51 +56,39 @@ struct _EWebViewPrivate {
GdkPixbufAnimation *cursor_image;
gchar *cursor_image_src;
+ GHashTable *js_callbacks;
+
+ GSList *highlights;
+
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 _EWebViewRequest {
- GFile *file;
- EWebView *web_view;
- GCancellable *cancellable;
- GInputStream *input_stream;
- GtkHTMLStream *output_stream;
- gchar buffer[4096];
+ guint caret_mode : 1;
};
enum {
PROP_0,
- PROP_ANIMATE,
PROP_CARET_MODE,
PROP_COPY_TARGET_LIST,
PROP_CURSOR_IMAGE,
PROP_CURSOR_IMAGE_SRC,
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
};
enum {
- COPY_CLIPBOARD,
- CUT_CLIPBOARD,
- PASTE_CLIPBOARD,
POPUP_EVENT,
STATUS_MESSAGE,
STOP_LOADING,
@@ -125,6 +120,7 @@ static const gchar *ui =
" <placeholder name='custom-actions-3'/>"
" <separator/>"
" <menuitem action='select-all'/>"
+" <placeholder name='inspect-menu' />"
" </popup>"
"</ui>";
@@ -135,7 +131,7 @@ static void e_web_view_selectable_init (ESelectableInterface *interface);
G_DEFINE_TYPE_WITH_CODE (
EWebView,
e_web_view,
- GTK_TYPE_HTML,
+ WEBKIT_TYPE_WEB_VIEW,
G_IMPLEMENT_INTERFACE (
E_TYPE_EXTENSIBLE, NULL)
G_IMPLEMENT_INTERFACE (
@@ -145,141 +141,6 @@ G_DEFINE_TYPE_WITH_CODE (
E_TYPE_SELECTABLE,
e_web_view_selectable_init))
-static EWebViewRequest *
-web_view_request_new (EWebView *web_view,
- const gchar *uri,
- GtkHTMLStream *stream)
-{
- EWebViewRequest *request;
- GList *list;
-
- request = g_slice_new (EWebViewRequest);
-
- /* 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_request_free (EWebViewRequest *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 (EWebViewRequest, request);
-}
-
-static void
-web_view_request_cancel (EWebViewRequest *request)
-{
- g_cancellable_cancel (request->cancellable);
-}
-
-static gboolean
-web_view_request_check_for_error (EWebViewRequest *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_request_free (request);
- g_error_free (error);
-
- return TRUE;
-}
-
-static void
-web_view_request_stream_read_cb (GInputStream *input_stream,
- GAsyncResult *result,
- EWebViewRequest *request)
-{
- gssize bytes_read;
- GError *error = NULL;
-
- bytes_read = g_input_stream_read_finish (input_stream, result, &error);
-
- if (web_view_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_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_request_stream_read_cb, request);
-}
-
-static void
-web_view_request_read_cb (GFile *file,
- GAsyncResult *result,
- EWebViewRequest *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_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_request_stream_read_cb, request);
-}
-
static void
action_copy_clipboard_cb (GtkAction *action,
EWebView *web_view)
@@ -470,71 +331,149 @@ static GtkActionEntry standard_entries[] = {
G_CALLBACK (action_select_all_cb) }
};
-static gboolean
-web_view_button_press_event_cb (EWebView *web_view,
- GdkEventButton *event,
- GtkHTML *frame)
+static void
+web_view_menu_item_select_cb (EWebView *web_view,
+ GtkWidget *widget)
{
- gboolean event_handled = FALSE;
- gchar *uri = NULL;
+ GtkAction *action;
+ GtkActivatable *activatable;
+ const gchar *tooltip;
- if (event) {
- GdkPixbufAnimation *anim;
- gchar *image_src;
+ activatable = GTK_ACTIVATABLE (widget);
+ action = gtk_activatable_get_related_action (activatable);
+ tooltip = gtk_action_get_tooltip (action);
- if (frame == NULL)
- frame = GTK_HTML (web_view);
+ if (tooltip == NULL)
+ return;
- anim = gtk_html_get_image_at (frame, event->x, event->y);
- e_web_view_set_cursor_image (web_view, anim);
- if (anim != NULL)
- g_object_unref (anim);
+ e_web_view_status_message (web_view, tooltip);
+}
- image_src = gtk_html_get_image_src_at (
- frame, event->x, event->y);
- e_web_view_set_cursor_image_src (web_view, image_src);
- g_free (image_src);
- }
+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) {
+ 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);
+ }
- if (event != NULL && event->button != 3)
- return FALSE;
+ } else {
- /* 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_is_selection_active (web_view))
- uri = e_web_view_extract_uri (web_view, event, frame);
+ WebKitDOMNode *child, *next_child;
- if (uri != NULL && g_str_has_prefix (uri, "##")) {
- g_free (uri);
- return FALSE;
- }
+ /* Iframe? Let's traverse inside! */
+ if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) {
- g_signal_emit (
- web_view, signals[POPUP_EVENT], 0,
- event, uri, &event_handled);
+ WebKitDOMDocument *frame_document;
- g_free (uri);
+ 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) {
+ next_child = webkit_dom_node_get_next_sibling (child);
+ replace_text (child, text, replacement);
+ child = next_child;
+ }
+ }
+ }
- return event_handled;
}
static void
-web_view_menu_item_select_cb (EWebView *web_view,
- GtkWidget *widget)
+web_view_update_document_highlights (EWebView *web_view)
{
- GtkAction *action;
- GtkActivatable *activatable;
- const gchar *tooltip;
+ WebKitDOMDocument *document;
+ GSList *iter;
- activatable = GTK_ACTIVATABLE (widget);
- action = gtk_activatable_get_related_action (activatable);
- tooltip = gtk_action_get_tooltip (action);
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
- if (tooltip == NULL)
- return;
+ for (iter = web_view->priv->highlights; iter; iter = iter->next) {
- e_web_view_status_message (web_view, tooltip);
+ WebKitDOMDocumentFragment *frag;
+ WebKitDOMElement *span;
+
+ span = webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_html_element_set_class_name (
+ WEBKIT_DOM_HTML_ELEMENT (span), "__evo-highlight");
+ 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
@@ -560,6 +499,86 @@ web_view_connect_proxy_cb (EWebView *web_view,
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 *web_view,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ WebKitLoadStatus status;
+
+ status = webkit_web_view_get_load_status (web_view);
+ if (status != WEBKIT_LOAD_FINISHED)
+ return;
+
+ web_view_update_document_highlights (E_WEB_VIEW (web_view));
+}
+
static void
web_view_set_property (GObject *object,
guint property_id,
@@ -567,12 +586,6 @@ web_view_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_ANIMATE:
- e_web_view_set_animate (
- E_WEB_VIEW (object),
- g_value_get_boolean (value));
- return;
-
case PROP_CARET_MODE:
e_web_view_set_caret_mode (
E_WEB_VIEW (object),
@@ -603,12 +616,6 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
- case PROP_EDITABLE:
- e_web_view_set_editable (
- E_WEB_VIEW (object),
- g_value_get_boolean (value));
- return;
-
case PROP_INLINE_SPELLING:
e_web_view_set_inline_spelling (
E_WEB_VIEW (object),
@@ -662,24 +669,12 @@ web_view_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_ANIMATE:
- g_value_set_boolean (
- value, e_web_view_get_animate (
- E_WEB_VIEW (object)));
- return;
-
case PROP_CARET_MODE:
g_value_set_boolean (
value, e_web_view_get_caret_mode (
E_WEB_VIEW (object)));
return;
- case PROP_COPY_TARGET_LIST:
- g_value_set_boxed (
- value, e_web_view_get_copy_target_list (
- E_WEB_VIEW (object)));
- return;
-
case PROP_CURSOR_IMAGE:
g_value_set_object (
value, e_web_view_get_cursor_image (
@@ -704,12 +699,6 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
- case PROP_EDITABLE:
- g_value_set_boolean (
- value, e_web_view_get_editable (
- E_WEB_VIEW (object)));
- return;
-
case PROP_INLINE_SPELLING:
g_value_set_boolean (
value, e_web_view_get_inline_spelling (
@@ -734,12 +723,6 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
- case PROP_PASTE_TARGET_LIST:
- g_value_set_boxed (
- value, e_web_view_get_paste_target_list (
- E_WEB_VIEW (object)));
- return;
-
case PROP_PRINT_PROXY:
g_value_set_object (
value, e_web_view_get_print_proxy (
@@ -789,16 +772,6 @@ web_view_dispose (GObject *object)
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;
@@ -809,6 +782,16 @@ web_view_dispose (GObject *object)
priv->cursor_image_src = NULL;
}
+ if (priv->js_callbacks != NULL) {
+ g_hash_table_destroy (priv->js_callbacks);
+ priv->js_callbacks = NULL;
+ }
+
+ if (priv->highlights != NULL) {
+ g_slist_free_full (priv->highlights, g_free);
+ priv->highlights = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -861,12 +844,103 @@ web_view_button_press_event (GtkWidget *widget,
{
GtkWidgetClass *widget_class;
EWebView *web_view;
+ gboolean event_handled = FALSE;
+ gchar *uri;
web_view = E_WEB_VIEW (widget);
- if (web_view_button_press_event_cb (web_view, event, NULL))
+ if (event) {
+ WebKitHitTestResult *test;
+ WebKitHitTestResultContext context;
+
+ if (web_view->priv->cursor_image) {
+ g_object_unref (web_view->priv->cursor_image);
+ web_view->priv->cursor_image = NULL;
+ }
+
+ if (web_view->priv->cursor_image_src) {
+ g_free (web_view->priv->cursor_image_src);
+ web_view->priv->cursor_image_src = NULL;
+ }
+
+ test = webkit_web_view_get_hit_test_result (WEBKIT_WEB_VIEW (web_view), event);
+
+ if (!test)
+ goto chainup;
+
+ g_object_get (G_OBJECT (test), "context", &context, NULL);
+ if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
+ WebKitWebDataSource *data_source;
+ WebKitWebFrame *frame;
+ GList *subresources, *res;
+
+ g_object_get (G_OBJECT (test), "image-uri", &uri, NULL);
+
+ if (!uri)
+ goto chainup;
+
+ if (web_view->priv->cursor_image_src)
+ 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)
+ 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)
+ 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;
+ }
+ }
+ }
+
+ if (event != NULL && event->button != 3)
+ goto chainup;
+
+ uri = e_web_view_extract_uri (web_view, event);
+
+ if (uri != NULL && g_str_has_prefix (uri, "##")) {
+ g_free (uri);
+ goto chainup;
+ }
+
+ g_signal_emit (
+ web_view, signals[POPUP_EVENT], 0,
+ event, uri, &event_handled);
+
+ g_free (uri);
+
+ if (event_handled)
return TRUE;
+chainup:
/* Chain up to parent's button_press_event() method. */
widget_class = GTK_WIDGET_CLASS (parent_class);
return widget_class->button_press_event (widget, event);
@@ -879,10 +953,10 @@ web_view_scroll_event (GtkWidget *widget,
if (event->state & GDK_CONTROL_MASK) {
switch (event->direction) {
case GDK_SCROLL_UP:
- gtk_html_zoom_in (GTK_HTML (widget));
+ e_web_view_zoom_in (E_WEB_VIEW (widget));
return TRUE;
case GDK_SCROLL_DOWN:
- gtk_html_zoom_out (GTK_HTML (widget));
+ e_web_view_zoom_out (E_WEB_VIEW (widget));
return TRUE;
default:
break;
@@ -892,74 +966,71 @@ web_view_scroll_event (GtkWidget *widget,
return FALSE;
}
-static void
-web_view_url_requested (GtkHTML *html,
- const gchar *uri,
- GtkHTMLStream *stream)
+static GtkWidget *
+web_view_create_plugin_widget (EWebView *web_view,
+ const gchar *mime_type,
+ const gchar *uri,
+ GHashTable *param)
{
- EWebViewRequest *request;
+ GtkWidget *widget = NULL;
- request = web_view_request_new (E_WEB_VIEW (html), uri, stream);
+ if (g_strcmp0 (mime_type, "image/x-themed-icon") == 0) {
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf;
+ gpointer data;
+ glong size = 0;
+ GError *error = NULL;
- g_file_read_async (
- request->file, G_PRIORITY_DEFAULT,
- request->cancellable, (GAsyncReadyCallback)
- web_view_request_read_cb, request);
-}
+ icon_theme = gtk_icon_theme_get_default ();
-static void
-web_view_gtkhtml_link_clicked (GtkHTML *html,
- const gchar *uri)
-{
- EWebViewClass *class;
- EWebView *web_view;
+ if (size == 0) {
+ data = g_hash_table_lookup (param, "width");
+ if (data != NULL)
+ size = MAX (size, strtol (data, NULL, 10));
+ }
- web_view = E_WEB_VIEW (html);
+ if (size == 0) {
+ data = g_hash_table_lookup (param, "height");
+ if (data != NULL)
+ size = MAX (size, strtol (data, NULL, 10));
+ }
- class = E_WEB_VIEW_GET_CLASS (web_view);
- g_return_if_fail (class->link_clicked != NULL);
+ 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);
+ }
+ }
- class->link_clicked (web_view, uri);
+ return widget;
}
-static void
-web_view_on_url (GtkHTML *html,
- const gchar *uri)
+static gchar *
+web_view_extract_uri (EWebView *web_view,
+ GdkEventButton *event)
{
- EWebViewClass *class;
- EWebView *web_view;
-
- web_view = E_WEB_VIEW (html);
-
- class = E_WEB_VIEW_GET_CLASS (web_view);
- g_return_if_fail (class->hovering_over_link != NULL);
+ WebKitHitTestResult *result;
+ WebKitHitTestResultContext context;
+ gchar *uri = NULL;
- /* XXX WebKit would supply a title here. */
- class->hovering_over_link (web_view, NULL, uri);
-}
+ result = webkit_web_view_get_hit_test_result (
+ WEBKIT_WEB_VIEW (web_view), event);
-static void
-web_view_iframe_created (GtkHTML *html,
- GtkHTML *iframe)
-{
- g_signal_connect_swapped (
- iframe, "button-press-event",
- G_CALLBACK (web_view_button_press_event_cb), html);
-}
+ g_object_get (result, "context", &context, "link-uri", &uri, NULL);
-static gchar *
-web_view_extract_uri (EWebView *web_view,
- GdkEventButton *event,
- GtkHTML *html)
-{
- gchar *uri;
+ if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+ return uri;
- if (event != NULL)
- uri = gtk_html_get_url_at (html, event->x, event->y);
- else
- uri = gtk_html_get_cursor_url (html);
+ g_free (uri);
- return uri;
+ return NULL;
}
static void
@@ -1030,30 +1101,62 @@ static void
web_view_load_string (EWebView *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_clear (web_view);
+ if (string == NULL)
+ string = "";
+
+ webkit_web_view_load_string (
+ WEBKIT_WEB_VIEW (web_view),
+ string, "text/html", "UTF-8", "file://");
}
static void
-web_view_copy_clipboard (EWebView *web_view)
+web_view_load_uri (EWebView *web_view,
+ const gchar *uri)
{
- gtk_html_command (GTK_HTML (web_view), "copy");
+ if (uri == NULL)
+ uri = "about:blank";
+
+ webkit_web_view_load_uri (
+ WEBKIT_WEB_VIEW (web_view), uri);
}
static void
-web_view_cut_clipboard (EWebView *web_view)
+web_view_frame_load_string (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *string)
{
- if (e_web_view_get_editable (web_view))
- gtk_html_command (GTK_HTML (web_view), "cut");
+ WebKitWebFrame *main_frame, *frame;
+
+ if (string == NULL)
+ string = "";
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ if (main_frame) {
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ if (frame)
+ webkit_web_frame_load_string (
+ frame, string, "text/html", "UTF-8", "file://");
+ }
}
static void
-web_view_paste_clipboard (EWebView *web_view)
+web_view_frame_load_uri (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *uri)
{
- if (e_web_view_get_editable (web_view))
- gtk_html_command (GTK_HTML (web_view), "paste");
+ WebKitWebFrame *main_frame, *frame;
+
+ if (uri == NULL)
+ uri = "about:blank";
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ if (main_frame) {
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ if (frame)
+ webkit_web_frame_load_uri (frame, uri);
+ }
}
static gboolean
@@ -1070,11 +1173,7 @@ web_view_popup_event (EWebView *web_view,
static void
web_view_stop_loading (EWebView *web_view)
{
- g_list_foreach (
- web_view->priv->requests, (GFunc)
- web_view_request_cancel, NULL);
-
- gtk_html_stop (GTK_HTML (web_view));
+ webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
}
static void
@@ -1267,48 +1366,27 @@ web_view_selectable_update_actions (ESelectable *selectable,
GdkAtom *clipboard_targets,
gint n_clipboard_targets)
{
- EWebView *web_view;
+ WebKitWebView *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 (selectable);
- editable = e_web_view_get_editable (web_view);
- have_selection = e_web_view_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;
+ web_view = WEBKIT_WEB_VIEW (selectable);
action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
- sensitive = editable && have_selection;
+ 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 = have_selection;
+ 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 = editable && can_paste;
+ 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);
@@ -1349,7 +1427,9 @@ e_web_view_class_init (EWebViewClass *class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
+#if 0 /* WEBKIT */
GtkHTMLClass *html_class;
+#endif
parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EWebViewPrivate));
@@ -1365,35 +1445,25 @@ e_web_view_class_init (EWebViewClass *class)
widget_class->button_press_event = web_view_button_press_event;
widget_class->scroll_event = web_view_scroll_event;
+#if 0 /* WEBKIT */
html_class = GTK_HTML_CLASS (class);
html_class->url_requested = web_view_url_requested;
- html_class->link_clicked = web_view_gtkhtml_link_clicked;
- html_class->on_url = web_view_on_url;
- html_class->iframe_created = web_view_iframe_created;
+#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->copy_clipboard = web_view_copy_clipboard;
- class->cut_clipboard = web_view_cut_clipboard;
- class->paste_clipboard = web_view_paste_clipboard;
+ 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_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",
@@ -1402,12 +1472,6 @@ e_web_view_class_init (EWebViewClass *class)
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_CURSOR_IMAGE,
@@ -1452,16 +1516,6 @@ e_web_view_class_init (EWebViewClass *class)
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",
@@ -1500,12 +1554,6 @@ e_web_view_class_init (EWebViewClass *class)
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,
@@ -1536,33 +1584,6 @@ e_web_view_class_init (EWebViewClass *class)
NULL,
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 (EWebViewClass, 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 (EWebViewClass, 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 (EWebViewClass, 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),
@@ -1634,26 +1655,46 @@ e_web_view_init (EWebView *web_view)
{
GtkUIManager *ui_manager;
GtkActionGroup *action_group;
- GtkTargetList *target_list;
EPopupAction *popup_action;
+ WebKitWebSettings *web_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, "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;
+ web_view->priv->js_callbacks = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free, NULL);
+
g_signal_connect_swapped (
ui_manager, "connect-proxy",
G_CALLBACK (web_view_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;
+ web_settings = e_web_view_get_default_settings (GTK_WIDGET (web_view));
+ e_web_view_set_settings (web_view, web_settings);
+ g_object_unref (web_settings);
action_group = gtk_action_group_new ("uri");
gtk_action_group_set_translation_domain (action_group, domain);
@@ -1763,6 +1804,7 @@ e_web_view_init (EWebView *web_view)
e_plugin_ui_enable_manager (ui_manager, id);
e_extensible_load_extensions (E_EXTENSIBLE (web_view));
+
}
GtkWidget *
@@ -1776,7 +1818,7 @@ e_web_view_clear (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_load_empty (GTK_HTML (web_view));
+ e_web_view_load_string (web_view, NULL);
}
void
@@ -1793,54 +1835,316 @@ e_web_view_load_string (EWebView *web_view,
class->load_string (web_view, string);
}
-gboolean
-e_web_view_get_animate (EWebView *web_view)
+void
+e_web_view_load_uri (EWebView *web_view,
+ const gchar *uri)
{
- /* XXX This is just here to maintain symmetry
- * with e_web_view_set_animate(). */
+ EWebViewClass *class;
- g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
- return gtk_html_get_animate (GTK_HTML (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_set_animate (EWebView *web_view,
- gboolean animate)
+e_web_view_reload (EWebView *web_view)
{
- /* 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 (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, *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) {
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ if (frame)
+ return webkit_web_frame_get_uri (frame);
+ }
+
+ return NULL;
+}
+
+gchar *
+e_web_view_get_html (EWebView *web_view)
+{
+ GValue html = {0};
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ if (e_web_view_exec_script (web_view, "return document.documentElement.innerHTML;", &html) == G_TYPE_STRING)
+ return g_strdup (g_value_get_string (&html));
+ else
+ return NULL;
+}
+
+JSGlobalContextRef
+e_web_view_get_global_context (EWebView *web_view)
+{
+ WebKitWebFrame *main_frame;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), 0);
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ return webkit_web_frame_get_global_context (main_frame);
+}
+
+GType
+e_web_view_exec_script (EWebView *web_view,
+ const gchar *script,
+ GValue *value)
+{
+ WebKitWebFrame *main_frame;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), G_TYPE_INVALID);
+ g_return_val_if_fail (script != NULL, G_TYPE_INVALID);
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+
+ return e_web_view_frame_exec_script (web_view,
+ webkit_web_frame_get_name (main_frame),
+ script, value);
+}
+
+GType
+e_web_view_frame_exec_script (EWebView *web_view,
+ const gchar *frame_name,
+ const gchar *script,
+ GValue *value)
+{
+ WebKitWebFrame *main_frame, *frame;
+ JSGlobalContextRef context;
+ JSValueRef js_value, error = NULL;
+ JSType js_type;
+ JSStringRef js_script;
+ JSStringRef js_str;
+ size_t str_len;
+ gchar *str;
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), G_TYPE_INVALID);
+ g_return_val_if_fail (script != NULL, G_TYPE_INVALID);
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ frame = webkit_web_frame_find_frame (main_frame, frame_name);
+
+ context = webkit_web_frame_get_global_context (frame);
+
+ js_script = JSStringCreateWithUTF8CString (script);
+ js_value = JSEvaluateScript (context, js_script, NULL, NULL, 0, &error);
+ JSStringRelease (js_script);
+
+ if (error) {
+ gchar *msg;
+ js_str = JSValueToStringCopy (context, error, NULL);
+ str_len = JSStringGetLength (js_str);
+
+ msg = g_malloc (str_len + 1);
+ JSStringGetUTF8CString (js_str, msg, str_len + 1);
+ JSStringRelease (js_str);
+
+ g_message ("JavaScript Execution Failed: %s", msg);
+ g_free (msg);
+
+ return G_TYPE_INVALID;
+ }
+
+ if (!value)
+ return G_TYPE_NONE;
+
+ js_type = JSValueGetType (context, js_value);
+ switch (js_type) {
+ case kJSTypeBoolean:
+ g_value_init (value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (value, JSValueToBoolean (context, js_value));
+ break;
+ case kJSTypeNumber:
+ g_value_init (value, G_TYPE_DOUBLE);
+ g_value_set_double (value, JSValueToNumber (context, js_value, NULL));
+ break;
+ case kJSTypeString:
+ js_str = JSValueToStringCopy (context, js_value, NULL);
+ str_len = JSStringGetLength (js_str);
+ str = g_malloc (str_len + 1);
+ JSStringGetUTF8CString (js_str, str, str_len + 1);
+ JSStringRelease (js_str);
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, str);
+ g_free (str);
+ break;
+ case kJSTypeObject:
+ g_value_init (value, G_TYPE_OBJECT);
+ g_value_set_object (value, JSValueToObject (context, js_value, NULL));
+ break;
+ case kJSTypeNull:
+ g_value_init (value, G_TYPE_POINTER);
+ g_value_set_pointer (value, NULL);
+ break;
+ case kJSTypeUndefined:
+ break;
+ }
+
+ return G_VALUE_TYPE (value);
+}
+
+static JSValueRef
+web_view_handle_js_callback (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argument_count,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ gpointer web_view;
+ gpointer user_data;
+ gchar *fnc_name;
+ size_t fnc_name_len;
+
+ EWebViewJSFunctionCallback callback;
+
+ JSStringRef js_webview_prop = JSStringCreateWithUTF8CString ("webview");
+ JSStringRef js_userdata_prop = JSStringCreateWithUTF8CString ("user-data");
+ JSStringRef js_fncname_prop = JSStringCreateWithUTF8CString ("fnc-name");
+ JSStringRef js_fncname_str;
+
+ JSValueRef js_webview = JSObjectGetProperty (ctx, function, js_webview_prop, NULL);
+ JSValueRef js_userdata = JSObjectGetProperty (ctx, function, js_userdata_prop, NULL);
+ JSValueRef js_fncname = JSObjectGetProperty (ctx, function, js_fncname_prop, NULL);
+
+ web_view = GINT_TO_POINTER ((gint) JSValueToNumber (ctx, js_webview, NULL));
+ user_data = GINT_TO_POINTER ((gint) JSValueToNumber (ctx, js_userdata, NULL));
+ js_fncname_str = JSValueToStringCopy (ctx, js_fncname, NULL);
+ fnc_name_len = JSStringGetLength (js_fncname_str);
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), 0);
+
+ /* Convert fncname to gchar* and lookup the callback in hashtable */
+ fnc_name = g_malloc (fnc_name_len + 1);
+ JSStringGetUTF8CString (js_fncname_str, fnc_name, fnc_name_len + 1);
+ callback = g_hash_table_lookup (E_WEB_VIEW (web_view)->priv->js_callbacks, fnc_name);
+
+ g_return_val_if_fail (callback != NULL, 0);
+
+ /* Call the callback function */
+ callback (E_WEB_VIEW (web_view), argument_count, arguments, user_data);
+
+ JSStringRelease (js_fncname_str);
+ JSStringRelease (js_fncname_prop);
+ JSStringRelease (js_webview_prop);
+ JSStringRelease (js_userdata_prop);
+
+ g_free (fnc_name);
+
+ return 0;
+}
+
+void
+e_web_view_install_js_callback (EWebView *web_view,
+ const gchar *fnc_name,
+ EWebViewJSFunctionCallback callback,
+ gpointer user_data)
+{
+ WebKitWebFrame *frame;
+ JSGlobalContextRef ctx;
+ JSObjectRef global_obj, js_func;
+ JSStringRef js_fnc_name, js_webview_prop, js_userdata_prop, js_fncname_prop;
g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (fnc_name != NULL);
+ g_return_if_fail (callback != NULL);
+
+ frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
+ ctx = webkit_web_frame_get_global_context (frame);
+ global_obj = JSContextGetGlobalObject (ctx);
+ js_fnc_name = JSStringCreateWithUTF8CString (fnc_name);
+ js_func = JSObjectMakeFunctionWithCallback (ctx, NULL,
+ (JSObjectCallAsFunctionCallback) web_view_handle_js_callback);
+ js_webview_prop = JSStringCreateWithUTF8CString ("webview");
+ js_userdata_prop = JSStringCreateWithUTF8CString ("user-data");
+ js_fncname_prop = JSStringCreateWithUTF8CString ("fnc-name");
- gtk_html_set_animate (GTK_HTML (web_view), animate);
+ /* Set some properties to the function */
+ JSObjectSetProperty (ctx, js_func, js_webview_prop, JSValueMakeNumber (ctx, GPOINTER_TO_INT (web_view)), 0, NULL);
+ JSObjectSetProperty (ctx, js_func, js_userdata_prop, JSValueMakeNumber (ctx, GPOINTER_TO_INT (user_data)), 0, NULL);
+ JSObjectSetProperty (ctx, js_func, js_fncname_prop, JSValueMakeString (ctx, js_fnc_name), 0, NULL);
- g_object_notify (G_OBJECT (web_view), "animate");
+ /* Set the function as a property of global object */
+ JSObjectSetProperty (ctx, global_obj, js_fnc_name, js_func, 0, NULL);
+
+ JSStringRelease (js_fncname_prop);
+ JSStringRelease (js_userdata_prop);
+ JSStringRelease (js_webview_prop);
+ JSStringRelease (js_fnc_name);
+
+ g_hash_table_insert (web_view->priv->js_callbacks, g_strdup (fnc_name), callback);
}
gboolean
e_web_view_get_caret_mode (EWebView *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 (web_view), FALSE);
- return gtk_html_get_caret_mode (GTK_HTML (web_view));
+ return web_view->priv->caret_mode;
}
void
e_web_view_set_caret_mode (EWebView *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 (web_view));
- gtk_html_set_caret_mode (GTK_HTML (web_view), caret_mode);
+ web_view->priv->caret_mode = caret_mode;
g_object_notify (G_OBJECT (web_view), "caret-mode");
}
@@ -1850,7 +2154,8 @@ e_web_view_get_copy_target_list (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- return web_view->priv->copy_target_list;
+ return webkit_web_view_get_copy_target_list (
+ WEBKIT_WEB_VIEW (web_view));
}
gboolean
@@ -1892,46 +2197,74 @@ e_web_view_set_disable_save_to_disk (EWebView *web_view,
}
gboolean
-e_web_view_get_editable (EWebView *web_view)
+e_web_view_get_enable_frame_flattening (EWebView * web_view)
{
- /* XXX This is just here to maintain symmetry
- * with e_web_view_set_editable(). */
+ 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 gtk_html_get_editable (GTK_HTML (web_view));
+ return webkit_web_view_get_editable (WEBKIT_WEB_VIEW (web_view));
}
void
e_web_view_set_editable (EWebView *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 (web_view));
- gtk_html_set_editable (GTK_HTML (web_view), editable);
-
- g_object_notify (G_OBJECT (web_view), "editable");
+ 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. */
@@ -1941,23 +2274,29 @@ e_web_view_set_inline_spelling (EWebView *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. */
@@ -1967,23 +2306,29 @@ e_web_view_set_magic_links (EWebView *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. */
@@ -1993,6 +2338,7 @@ e_web_view_set_magic_smileys (EWebView *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 *
@@ -2092,7 +2438,8 @@ e_web_view_get_paste_target_list (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- return web_view->priv->paste_target_list;
+ return webkit_web_view_get_paste_target_list (
+ WEBKIT_WEB_VIEW (web_view));
}
GtkAction *
@@ -2149,6 +2496,40 @@ e_web_view_set_save_as_proxy (EWebView *web_view,
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)
@@ -2179,20 +2560,16 @@ e_web_view_get_action_group (EWebView *web_view,
gchar *
e_web_view_extract_uri (EWebView *web_view,
- GdkEventButton *event,
- GtkHTML *frame)
+ GdkEventButton *event)
{
EWebViewClass *class;
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- if (frame == NULL)
- frame = GTK_HTML (web_view);
-
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, frame);
+ return class->extract_uri (web_view, event);
}
void
@@ -2200,7 +2577,7 @@ e_web_view_copy_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- g_signal_emit (web_view, signals[COPY_CLIPBOARD], 0);
+ webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
}
void
@@ -2208,7 +2585,7 @@ e_web_view_cut_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- g_signal_emit (web_view, signals[CUT_CLIPBOARD], 0);
+ webkit_web_view_cut_clipboard (WEBKIT_WEB_VIEW (web_view));
}
gboolean
@@ -2216,7 +2593,7 @@ e_web_view_is_selection_active (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
- return gtk_html_command (GTK_HTML (web_view), "is-selection-active");
+ return webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view));
}
void
@@ -2224,7 +2601,7 @@ e_web_view_paste_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- g_signal_emit (web_view, signals[PASTE_CLIPBOARD], 0);
+ webkit_web_view_paste_clipboard (WEBKIT_WEB_VIEW (web_view));
}
gboolean
@@ -2232,7 +2609,10 @@ e_web_view_scroll_forward (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
- return gtk_html_command (GTK_HTML (web_view), "scroll-forward");
+ webkit_web_view_move_cursor (
+ WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, 1);
+
+ return TRUE; /* XXX This means nothing. */
}
gboolean
@@ -2240,7 +2620,10 @@ e_web_view_scroll_backward (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
- return gtk_html_command (GTK_HTML (web_view), "scroll-backward");
+ webkit_web_view_move_cursor (
+ WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, -1);
+
+ return TRUE; /* XXX This means nothing. */
}
void
@@ -2248,15 +2631,17 @@ e_web_view_select_all (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_command (GTK_HTML (web_view), "select-all");
+ 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
@@ -2264,7 +2649,7 @@ e_web_view_zoom_100 (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_command (GTK_HTML (web_view), "zoom-reset");
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0);
}
void
@@ -2272,7 +2657,7 @@ e_web_view_zoom_in (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_command (GTK_HTML (web_view), "zoom-in");
+ webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
}
void
@@ -2280,7 +2665,7 @@ e_web_view_zoom_out (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_command (GTK_HTML (web_view), "zoom-out");
+ webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
}
GtkUIManager *
@@ -2354,3 +2739,84 @@ e_web_view_update_actions (EWebView *web_view)
g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0);
}
+
+gchar *
+e_web_view_get_selection_html (EWebView *web_view)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *window;
+ WebKitDOMDOMSelection *selection;
+ WebKitDOMRange *range;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMHTMLElement *element;
+
+ 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));
+ window = webkit_dom_document_get_default_view (document);
+ selection = webkit_dom_dom_window_get_selection (window);
+ if (!selection)
+ return NULL;
+
+ range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
+ if (!range)
+ return NULL;
+
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+ if (!fragment)
+ return NULL;
+
+ element = WEBKIT_DOM_HTML_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 (element);
+}
+
+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 (GtkWidget *parent_widget)
+{
+ GtkStyleContext *context;
+ const PangoFontDescription *font;
+ WebKitWebSettings *settings;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (parent_widget), NULL);
+
+ settings = webkit_web_settings_new ();
+
+ /* Use same font-size as rest of Evolution */
+ context = gtk_widget_get_style_context (parent_widget);
+ font = gtk_style_context_get_font (context, GTK_STATE_FLAG_NORMAL);
+
+ g_object_set (G_OBJECT (settings),
+ "default-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
+ "default-monospace-font-size", (pango_font_description_get_size (font) / PANGO_SCALE),
+ "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;
+}