[evolution] I#1286 - WebView: Change how scheme handlers are registered
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] I#1286 - WebView: Change how scheme handlers are registered
- Date: Thu, 7 Jan 2021 11:03:53 +0000 (UTC)
commit a457b9f06a89d0ad93209e9a002f75f45cb5d211
Author: Milan Crha <mcrha redhat com>
Date: Thu Jan 7 12:03:05 2021 +0100
I#1286 - WebView: Change how scheme handlers are registered
Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/1286
src/e-util/e-web-view.c | 270 +++++++++++++++++-----------
src/modules/webkit-editor/e-webkit-editor.c | 78 +++++---
2 files changed, 217 insertions(+), 131 deletions(-)
---
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index d4a226c30e..b19eb7f8ac 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -75,6 +75,7 @@ struct _EWebViewPrivate {
gulong font_name_changed_handler_id;
gulong monospace_font_name_changed_handler_id;
+ GHashTable *scheme_handlers; /* gchar *scheme ~> EContentRequest */
GHashTable *old_settings;
WebKitFindController *find_controller;
@@ -83,8 +84,6 @@ struct _EWebViewPrivate {
gboolean has_hover_link;
- GSList *content_requests; /* EContentRequest * */
-
GHashTable *element_clicked_cbs; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
gboolean has_selection;
@@ -876,6 +875,146 @@ find_property (guint n_properties,
return NULL;
}
+static void
+web_view_uri_request_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WebKitURISchemeRequest *request = user_data;
+ GInputStream *stream = NULL;
+ gint64 stream_length = -1;
+ gchar *mime_type = NULL;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_REQUEST (source_object));
+ g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
+
+ if (!e_content_request_process_finish (E_CONTENT_REQUEST (source_object),
+ result, &stream, &stream_length, &mime_type, &error)) {
+ webkit_uri_scheme_request_finish_error (request, error);
+ g_clear_error (&error);
+ } else {
+ webkit_uri_scheme_request_finish (request, stream, stream_length, mime_type);
+
+ g_clear_object (&stream);
+ g_free (mime_type);
+ }
+
+ g_object_unref (request);
+}
+
+static void
+e_web_view_process_uri_request (EWebView *web_view,
+ WebKitURISchemeRequest *request)
+{
+ EContentRequest *content_request;
+ const gchar *scheme;
+ const gchar *uri;
+ gchar *redirect_to_uri = NULL;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
+
+ scheme = webkit_uri_scheme_request_get_scheme (request);
+ g_return_if_fail (scheme != NULL);
+
+ content_request = g_hash_table_lookup (web_view->priv->scheme_handlers, scheme);
+
+ if (!content_request) {
+ g_warning ("%s: Cannot find handler for scheme '%s'", G_STRFUNC, scheme);
+ return;
+ }
+
+ uri = webkit_uri_scheme_request_get_uri (request);
+
+ g_return_if_fail (e_content_request_can_process_uri (content_request, uri));
+
+ /* Expects an empty string to abandon the request,
+ or NULL to keep the passed-in uri,
+ or a new uri to load instead. */
+ g_signal_emit (web_view, signals[URI_REQUESTED], 0, uri, &redirect_to_uri);
+
+ if (redirect_to_uri && *redirect_to_uri) {
+ uri = redirect_to_uri;
+ } else if (redirect_to_uri) {
+ GError *error;
+
+ g_free (redirect_to_uri);
+
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
+
+ webkit_uri_scheme_request_finish_error (request, error);
+ g_clear_error (&error);
+
+ return;
+ }
+
+ e_content_request_process (content_request, uri, G_OBJECT (web_view), web_view->priv->cancellable,
+ web_view_uri_request_done_cb, g_object_ref (request));
+
+ g_free (redirect_to_uri);
+}
+
+static void
+web_view_process_uri_request_cb (WebKitURISchemeRequest *request,
+ gpointer user_data)
+{
+ WebKitWebView *web_view;
+
+ web_view = webkit_uri_scheme_request_get_web_view (request);
+
+ if (E_IS_WEB_VIEW (web_view)) {
+ e_web_view_process_uri_request (E_WEB_VIEW (web_view), request);
+ } else {
+ GError *error;
+
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, "Unexpected WebView type");
+ webkit_uri_scheme_request_finish_error (request, error);
+ g_clear_error (&error);
+
+ g_warning ("%s: Unexpected WebView type '%s' received", G_STRFUNC, web_view ?
G_OBJECT_TYPE_NAME (web_view) : "null");
+
+ return;
+ }
+}
+
+static GSList *known_schemes = NULL;
+
+static void
+web_view_web_context_gone (gpointer user_data,
+ GObject *obj)
+{
+ gpointer *pweb_context = user_data;
+
+ g_return_if_fail (pweb_context != NULL);
+
+ *pweb_context = NULL;
+
+ g_slist_free_full (known_schemes, g_free);
+ known_schemes = NULL;
+}
+
+static void
+web_view_ensure_scheme_known (WebKitWebContext *web_context,
+ const gchar *scheme)
+{
+ GSList *link;
+
+ g_return_if_fail (WEBKIT_IS_WEB_CONTEXT (web_context));
+ g_return_if_fail (scheme != NULL);
+
+ for (link = known_schemes; link; link = g_slist_next (link)) {
+ if (g_strcmp0 (scheme, link->data) == 0)
+ break;
+ }
+
+ if (!link) {
+ known_schemes = g_slist_prepend (known_schemes, g_strdup (scheme));
+
+ webkit_web_context_register_uri_scheme (web_context, scheme, web_view_process_uri_request_cb,
NULL, NULL);
+ }
+}
+
static GObject*
web_view_constructor (GType type,
guint n_construct_properties,
@@ -897,11 +1036,12 @@ web_view_constructor (GType type,
g_value_take_object (param->value, webkit_user_content_manager_new ());
param_spec = g_object_class_find_property (object_class, "web-context");
if ((param = find_property (n_construct_properties, construct_properties, param_spec))) {
- /* Share one web_context between all editors, thus there is one WebProcess
- for all the editors (and one for the preview). */
+ /* Share one web_context between all previews. */
static gpointer web_context = NULL;
if (!web_context) {
+ GSList *link;
+
web_context = webkit_web_context_new ();
webkit_web_context_set_cache_model (web_context,
WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
@@ -912,7 +1052,13 @@ web_view_constructor (GType type,
webkit_web_context_add_path_to_sandbox (web_context,
EVOLUTION_SOURCE_WEBKITDATADIR, TRUE);
#endif
- g_object_add_weak_pointer (G_OBJECT (web_context), &web_context);
+ g_object_weak_ref (G_OBJECT (web_context), web_view_web_context_gone,
&web_context);
+
+ for (link = known_schemes; link; link = g_slist_next (link)) {
+ const gchar *scheme = link->data;
+
+ webkit_web_context_register_uri_scheme (web_context, scheme,
web_view_process_uri_request_cb, NULL, NULL);
+ }
} else {
g_object_ref (web_context);
}
@@ -1128,11 +1274,9 @@ web_view_dispose (GObject *object)
priv->failed_to_find_text_handler_id = 0;
}
+ g_hash_table_remove_all (priv->scheme_handlers);
g_hash_table_remove_all (priv->element_clicked_cbs);
- g_slist_free_full (priv->content_requests, g_object_unref);
- priv->content_requests = NULL;
-
g_clear_object (&priv->ui_manager);
g_clear_object (&priv->open_proxy);
g_clear_object (&priv->print_proxy);
@@ -1162,120 +1306,26 @@ web_view_finalize (GObject *object)
g_clear_pointer (&priv->old_settings, g_hash_table_destroy);
+ g_hash_table_destroy (priv->scheme_handlers);
g_hash_table_destroy (priv->element_clicked_cbs);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
}
-static void
-web_view_uri_request_done_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
-{
- WebKitURISchemeRequest *request = user_data;
- GInputStream *stream = NULL;
- gint64 stream_length = -1;
- gchar *mime_type = NULL;
- GError *error = NULL;
-
- g_return_if_fail (E_IS_CONTENT_REQUEST (source_object));
- g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
-
- if (!e_content_request_process_finish (E_CONTENT_REQUEST (source_object),
- result, &stream, &stream_length, &mime_type, &error)) {
- webkit_uri_scheme_request_finish_error (request, error);
- g_clear_error (&error);
- } else {
- webkit_uri_scheme_request_finish (request, stream, stream_length, mime_type);
-
- g_clear_object (&stream);
- g_free (mime_type);
- }
-
- g_object_unref (request);
-}
-
-static void
-web_view_process_uri_request_cb (WebKitURISchemeRequest *request,
- gpointer user_data)
-{
- EWebView *web_view = NULL;
- EContentRequest *content_request = user_data;
- const gchar *uri;
- gchar *redirect_to_uri = NULL;
- GObject *requester;
-
- g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
- g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
-
- uri = webkit_uri_scheme_request_get_uri (request);
- requester = G_OBJECT (webkit_uri_scheme_request_get_web_view (request));
-
- if (!requester) {
- GError *error;
-
- error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
- webkit_uri_scheme_request_finish_error (request, error);
- g_clear_error (&error);
-
- return;
- }
-
- g_return_if_fail (e_content_request_can_process_uri (content_request, uri));
-
- if (E_IS_WEB_VIEW (requester)) {
- /* Expects an empty string to abandon the request,
- or NULL to keep the passed-in uri,
- or a new uri to load instead. */
- g_signal_emit (requester, signals[URI_REQUESTED], 0, uri, &redirect_to_uri);
-
- if (redirect_to_uri && *redirect_to_uri) {
- uri = redirect_to_uri;
- } else if (redirect_to_uri) {
- GError *error;
-
- g_free (redirect_to_uri);
-
- error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
-
- webkit_uri_scheme_request_finish_error (request, error);
- g_clear_error (&error);
-
- return;
- }
-
- web_view = E_WEB_VIEW (requester);
- }
-
- e_content_request_process (content_request, uri, requester, web_view ? web_view->priv->cancellable :
NULL,
- web_view_uri_request_done_cb, g_object_ref (request));
-
- g_free (redirect_to_uri);
-}
-
/* 'scheme' is like "file", not "file:" */
void
e_web_view_register_content_request_for_scheme (EWebView *web_view,
const gchar *scheme,
EContentRequest *content_request)
{
- WebKitWebContext *web_context;
-
g_return_if_fail (E_IS_WEB_VIEW (web_view));
g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
g_return_if_fail (scheme != NULL);
- web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (web_view));
-
- webkit_web_context_register_uri_scheme (web_context, scheme, web_view_process_uri_request_cb,
- g_object_ref (content_request), g_object_unref);
+ g_hash_table_insert (web_view->priv->scheme_handlers, g_strdup (scheme), g_object_ref
(content_request));
- if (!g_slist_find (web_view->priv->content_requests, content_request)) {
- web_view->priv->content_requests = g_slist_prepend (
- web_view->priv->content_requests,
- g_object_ref (content_request));
- }
+ web_view_ensure_scheme_known (webkit_web_view_get_context (WEBKIT_WEB_VIEW (web_view)), scheme);
}
static void
@@ -2387,6 +2437,7 @@ e_web_view_init (EWebView *web_view)
web_view->priv->highlights_enabled = TRUE;
web_view->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_variant_unref);
+ web_view->priv->scheme_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
g_object_unref);
g_signal_connect (
web_view, "context-menu",
@@ -4028,15 +4079,18 @@ e_web_view_request (EWebView *web_view,
{
EContentRequest *content_request = NULL;
AsyncContext *async_context;
- GSList *link;
+ GHashTableIter iter;
GTask *task;
gboolean is_processed = FALSE;
+ gpointer value;
g_return_if_fail (E_IS_WEB_VIEW (web_view));
g_return_if_fail (uri != NULL);
- for (link = web_view->priv->content_requests; link; link = g_slist_next (link)) {
- EContentRequest *adept = link->data;
+ g_hash_table_iter_init (&iter, web_view->priv->scheme_handlers);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ EContentRequest *adept = value;
if (!E_IS_CONTENT_REQUEST (adept) ||
!e_content_request_can_process_uri (adept, uri))
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index efe69a6276..c35b5bb8b7 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -78,6 +78,7 @@ struct _EWebKitEditorPrivate {
EContentEditorInitializedCallback initialized_callback;
gpointer initialized_user_data;
+ GHashTable *scheme_handlers; /* const gchar *scheme ~> EContentRequest */
GCancellable *cancellable;
gboolean html_mode;
@@ -3863,18 +3864,16 @@ static void
webkit_editor_process_uri_request_cb (WebKitURISchemeRequest *request,
gpointer user_data)
{
+ WebKitWebView *web_view;
EWebKitEditor *wk_editor;
- EContentRequest *content_request = user_data;
- const gchar *uri;
- GObject *requester;
+ EContentRequest *content_request;
+ const gchar *uri, *scheme;
g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
- g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
- uri = webkit_uri_scheme_request_get_uri (request);
- requester = G_OBJECT (webkit_uri_scheme_request_get_web_view (request));
+ web_view = webkit_uri_scheme_request_get_web_view (request);
- if (!requester) {
+ if (!web_view) {
GError *error;
error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
@@ -3884,11 +3883,35 @@ webkit_editor_process_uri_request_cb (WebKitURISchemeRequest *request,
return;
}
- g_return_if_fail (e_content_request_can_process_uri (content_request, uri));
+ wk_editor = E_IS_WEBKIT_EDITOR (web_view) ? E_WEBKIT_EDITOR (web_view) : NULL;
- wk_editor = E_IS_WEBKIT_EDITOR (requester) ? E_WEBKIT_EDITOR (requester) : NULL;
+ if (!wk_editor) {
+ GError *error;
+
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, "Unexpected WebView type");
+ webkit_uri_scheme_request_finish_error (request, error);
+ g_clear_error (&error);
- e_content_request_process (content_request, uri, requester, wk_editor ? wk_editor->priv->cancellable
: NULL,
+ g_warning ("%s: Unexpected WebView type '%s' received", G_STRFUNC, web_view ?
G_OBJECT_TYPE_NAME (web_view) : "null");
+
+ return;
+ }
+
+ scheme = webkit_uri_scheme_request_get_scheme (request);
+ g_return_if_fail (scheme != NULL);
+
+ content_request = g_hash_table_lookup (wk_editor->priv->scheme_handlers, scheme);
+
+ if (!content_request) {
+ g_warning ("%s: Cannot find handler for scheme '%s'", G_STRFUNC, scheme);
+ return;
+ }
+
+ uri = webkit_uri_scheme_request_get_uri (request);
+
+ g_return_if_fail (e_content_request_can_process_uri (content_request, uri));
+
+ e_content_request_process (content_request, uri, G_OBJECT (web_view), wk_editor ?
wk_editor->priv->cancellable : NULL,
webkit_editor_uri_request_done_cb, g_object_ref (request));
}
@@ -4104,21 +4127,13 @@ webkit_editor_constructed (GObject *object)
webkit_web_context_set_spell_checking_languages (web_context, (const gchar * const *) languages);
g_strfreev (languages);
- content_request = e_cid_request_new ();
- webkit_web_context_register_uri_scheme (web_context, "cid", webkit_editor_process_uri_request_cb,
- g_object_ref (content_request), g_object_unref);
- g_object_unref (content_request);
-
- content_request = e_file_request_new ();
- webkit_web_context_register_uri_scheme (web_context, "evo-file", webkit_editor_process_uri_request_cb,
- g_object_ref (content_request), g_object_unref);
- g_object_unref (content_request);
+ /* When adding new scheme handlers add them also into webkit_editor_constructor() */
+ g_hash_table_insert (wk_editor->priv->scheme_handlers, (gpointer) "cid", e_cid_request_new ());
+ g_hash_table_insert (wk_editor->priv->scheme_handlers, (gpointer) "evo-file", e_file_request_new ());
content_request = e_http_request_new ();
- webkit_web_context_register_uri_scheme (web_context, "evo-http", webkit_editor_process_uri_request_cb,
- g_object_ref (content_request), g_object_unref);
- webkit_web_context_register_uri_scheme (web_context, "evo-https",
webkit_editor_process_uri_request_cb,
- g_object_ref (content_request), g_object_unref);
+ g_hash_table_insert (wk_editor->priv->scheme_handlers, (gpointer) "evo-http", g_object_ref
(content_request));
+ g_hash_table_insert (wk_editor->priv->scheme_handlers, (gpointer) "evo-https", g_object_ref
(content_request));
g_object_unref (content_request);
webkit_web_view_set_editable (web_view, TRUE);
@@ -4211,6 +4226,14 @@ webkit_editor_constructor (GType type,
static gpointer web_context = NULL;
if (!web_context) {
+ const gchar *schemes[] = {
+ "cid",
+ "evo-file",
+ "evo-http",
+ "evo-https"
+ };
+ gint ii;
+
web_context = webkit_web_context_new ();
webkit_web_context_set_cache_model (web_context,
WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
@@ -4222,6 +4245,10 @@ webkit_editor_constructor (GType type,
#endif
g_object_add_weak_pointer (G_OBJECT (web_context), &web_context);
+
+ for (ii = 0; ii < G_N_ELEMENTS (schemes); ii++) {
+ webkit_web_context_register_uri_scheme (web_context, schemes[ii],
webkit_editor_process_uri_request_cb, NULL, NULL);
+ }
} else {
g_object_ref (web_context);
}
@@ -4275,6 +4302,8 @@ webkit_editor_dispose (GObject *object)
webkit_editor_finish_search (E_WEBKIT_EDITOR (object));
+ g_hash_table_remove_all (priv->scheme_handlers);
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_webkit_editor_parent_class)->dispose (object);
}
@@ -4313,6 +4342,8 @@ webkit_editor_finalize (GObject *object)
g_free (priv->font_name);
g_free (priv->context_menu_caret_word);
+ g_hash_table_destroy (priv->scheme_handlers);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_webkit_editor_parent_class)->finalize (object);
}
@@ -5551,6 +5582,7 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
/* To be able to cancel any pending calls when 'dispose' is called. */
wk_editor->priv->cancellable = g_cancellable_new ();
+ wk_editor->priv->scheme_handlers = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
g_object_unref);
wk_editor->priv->is_malfunction = FALSE;
wk_editor->priv->spell_check_enabled = TRUE;
wk_editor->priv->spell_checker = e_spell_checker_new ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]