summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcos Chavarría Teijeiro <chavarria1991@gmail.com>2014-09-12 10:00:50 +0200
committerDavid King <amigadave@amigadave.com>2015-06-22 13:32:34 +0100
commit04683e89cef14f56e4c3d1595424e109f12f5d06 (patch)
tree1da0c7f6e2562018a8be707006bbb6e69e5d90f9
parent3598be880e631b1cd43164f3dd2e48bb8fa53976 (diff)
downloadyelp-04683e89cef14f56e4c3d1595424e109f12f5d06.tar.gz
yelp-view: Implement pages load in WebKit2
Substitute webkit_web_view_load_string call for webkit_web_view_load_html for showing error pages. Implement custom uri schemes for loading the normal pages. We should deal with the uris that Yelp undestand and the uris that Webkit undestand so we have created functions to convert from one to the others. In addition, we should add a hack to be able to load absolute uris. When we have a help:gnome-help/... uri on our document and the current page has the same scheme (help) WebKit interprets this uri as relative and it builds a different uri. To fix this instead of use a help scheme we use a bogus-help schme so WebKit interprets the uri as absolute.
-rw-r--r--libyelp/Makefile.am2
-rw-r--r--libyelp/yelp-document.c11
-rw-r--r--libyelp/yelp-uri-builder.c127
-rw-r--r--libyelp/yelp-uri-builder.h30
-rw-r--r--libyelp/yelp-view.c804
-rw-r--r--libyelp/yelp-view.h5
6 files changed, 590 insertions, 389 deletions
diff --git a/libyelp/Makefile.am b/libyelp/Makefile.am
index e721fd5a..fc8131f3 100644
--- a/libyelp/Makefile.am
+++ b/libyelp/Makefile.am
@@ -24,6 +24,7 @@ libyelp_la_SOURCES = \
yelp-transform.c \
yelp-uri.c \
yelp-types.c \
+ yelp-uri-builder.c \
yelp-view.c
EXTRA_DIST = \
@@ -75,6 +76,7 @@ libyelp_headers = \
yelp-storage.h \
yelp-transform.h \
yelp-uri.h \
+ yelp-uri-builder.h \
yelp-view.h
libyelp_includedir = $(includedir)/libyelp/
diff --git a/libyelp/yelp-document.c b/libyelp/yelp-document.c
index fbb9e160..0ee1219f 100644
--- a/libyelp/yelp-document.c
+++ b/libyelp/yelp-document.c
@@ -842,9 +842,14 @@ document_request_page (YelpDocument *document,
else
request->page_id = g_strdup (page_id);
- request->cancellable = g_object_ref (cancellable);
- g_signal_connect (cancellable, "cancelled",
- G_CALLBACK (request_cancel), request);
+ if (cancellable) {
+ request->cancellable = g_object_ref (cancellable);
+ g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (request_cancel), request);
+ }
+ else {
+ request->cancellable = NULL;
+ }
request->callback = callback;
request->user_data = user_data;
diff --git a/libyelp/yelp-uri-builder.c b/libyelp/yelp-uri-builder.c
new file mode 100644
index 00000000..3c195e03
--- /dev/null
+++ b/libyelp/yelp-uri-builder.c
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "yelp-uri-builder.h"
+
+#define BOGUS_PREFIX "bogus-"
+#define BOGUS_PREFIX_LEN 6
+
+gchar *
+build_network_uri (YelpUri *uri, YelpDocument *document)
+{
+ SoupURI *soup_uri;
+ gchar *bogus_scheme;
+ gchar *canonical;
+ gchar *path;
+ gchar *retval;
+
+ canonical = yelp_uri_get_canonical_uri (uri);
+ soup_uri = soup_uri_new (canonical);
+ g_free (canonical);
+
+ /* Build the URI that will be passed to WebKit. Relative URIs will be
+ automatically reolved by WebKit, so we need to add a leading slash to
+ help: and ghelp: URIs to be considered as absolute by WebKit. The last
+ component of the URI is considered as a file by WebKit, unless there's
+ a trailing slash. For help: URIs this assumption is always correct, because
+ the page ID is part of the URI, and when resolved by WebKit, the page ID is
+ removed and the relative path is appended to the document URI. For ghelp: URIs
+ where the page ID is part of the query, we need to add a slash after the
+ document URI so that it's considered a directory and the relative path is appended
+ to the document URI.
+ */
+ if (g_str_equal (soup_uri->scheme, "ghelp") || g_str_equal (soup_uri->scheme, "gnome-help")) {
+ /* Pages are part of the query, add leading and trailing slash */
+ path = g_strdup_printf ("/%s/", soup_uri->path);
+ soup_uri_set_path (soup_uri, path);
+ g_free (path);
+ }
+ else if (g_str_equal (soup_uri->scheme, "help")) {
+ /* Page is part of the path, add only leading slash */
+ path = g_strdup_printf ("/%s", soup_uri->path);
+ soup_uri_set_path (soup_uri, path);
+ g_free (path);
+ }
+
+ /* We don't have actual page and frag IDs for DocBook. We just map IDs
+ of block elements. The result is that we get xref:someid#someid.
+ If someid is really the page ID, we just drop the frag reference.
+ Otherwise, normal page views scroll past the link trail.
+ */
+ if (soup_uri->fragment && YELP_IS_DOCBOOK_DOCUMENT (document)) {
+ gchar *page_id = yelp_uri_get_page_id (uri);
+ gchar *real_id = yelp_document_get_page_id (document, page_id);
+
+ if (g_str_equal (real_id, soup_uri->fragment))
+ soup_uri_set_fragment (soup_uri, NULL);
+
+ g_free (real_id);
+ g_free (page_id);
+ }
+
+ /* We need to use a different scheme from help or ghelp to be able to deal
+ with absolute uris in the HTML. Help uri schemes are help:gnome-help/...
+ they dont have a slash after the colon so WebKit resolves them as a relative
+ url when they are not. This doesn't happen if the current page URI has a different
+ scheme from absolute uri scheme.
+ */
+ bogus_scheme = build_network_scheme (soup_uri->scheme);
+ soup_uri_set_scheme (soup_uri, bogus_scheme);
+
+ retval = soup_uri_to_string (soup_uri, FALSE);
+ soup_uri_free (soup_uri);
+ g_free (bogus_scheme);
+
+ return retval;
+}
+
+gchar *
+build_yelp_uri (const gchar *uri_str)
+{
+ gchar *resource;
+ int path_len;
+ gchar *uri = g_strdup (uri_str);
+
+ if (!g_str_has_prefix (uri, BOGUS_PREFIX "ghelp:/") &&
+ !g_str_has_prefix (uri, BOGUS_PREFIX "gnome-help:/") &&
+ !g_str_has_prefix (uri, BOGUS_PREFIX "help:/")) {
+ return uri;
+ }
+
+ memmove (uri, uri + BOGUS_PREFIX_LEN, strlen (uri) - BOGUS_PREFIX_LEN + 1);
+
+ /* Remove the leading slash */
+ resource = strstr (uri, ":");
+ resource++;
+ memmove (resource, resource + 1, strlen (resource));
+
+ /*Remove the last / if any */
+ path_len = strlen (uri);
+ if (uri[path_len - 1] == '/')
+ uri[path_len - 1] = '\0';
+
+ return uri;
+}
+
+gchar *
+build_network_scheme (const gchar *scheme)
+{
+ return g_strdup_printf (BOGUS_PREFIX "%s", scheme);
+} \ No newline at end of file
diff --git a/libyelp/yelp-uri-builder.h b/libyelp/yelp-uri-builder.h
new file mode 100644
index 00000000..d6ca5d28
--- /dev/null
+++ b/libyelp/yelp-uri-builder.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <libsoup/soup.h>
+
+#include "yelp-document.h"
+#include "yelp-docbook-document.h"
+#include "yelp-uri.h"
+
+gchar * build_network_uri (YelpUri *uri, YelpDocument *document);
+gchar * build_yelp_uri (const gchar *uri);
+gchar * build_network_scheme (const gchar *scheme); \ No newline at end of file
diff --git a/libyelp/yelp-view.c b/libyelp/yelp-view.c
index cca02b9f..cb2b5bc3 100644
--- a/libyelp/yelp-view.c
+++ b/libyelp/yelp-view.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
+ * Copyright (C) 2014 Igalia S.L.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -38,99 +39,92 @@
#include "yelp-settings.h"
#include "yelp-types.h"
#include "yelp-view.h"
-
-#define BOGUS_URI "file:///bogus/"
-#define BOGUS_URI_LEN 14
-
-static void yelp_view_dispose (GObject *object);
-static void yelp_view_finalize (GObject *object);
-static void yelp_view_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void yelp_view_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-
-static gboolean view_external_uri (YelpView *view,
- YelpUri *uri);
-static void view_install_uri (YelpView *view,
- const gchar *uri);
-static void view_scrolled (GtkAdjustment *adjustment,
- YelpView *view);
-static void view_set_hadjustment (YelpView *view,
- GParamSpec *pspec,
- gpointer data);
-static void view_set_vadjustment (YelpView *view,
- GParamSpec *pspec,
- gpointer data);
-static void popup_open_link (GtkAction *action,
- YelpView *view);
-static void popup_open_link_new (GtkAction *action,
- YelpView *view);
-static void popup_copy_link (GtkAction *action,
- YelpView *view);
-static void popup_save_image (GtkAction *action,
- YelpView *view);
-static void popup_send_image (GtkAction *action,
- YelpView *view);
-static void popup_copy_code (GtkAction *action,
- YelpView *view);
-static void popup_save_code (GtkAction *action,
- YelpView *view);
-static void popup_copy_clipboard (GtkAction *action,
- YelpView *view);
-static gboolean view_populate_context_menu (YelpView *view,
- WebKitContextMenu *context_menu,
- GdkEvent *event,
- WebKitHitTestResult *hit_test_result,
- gpointer user_data);
-static gboolean view_script_dialog (YelpView *view,
- WebKitScriptDialog *dialog,
- gpointer data);
-static gboolean view_policy_decision_requested (YelpView *view,
- WebKitPolicyDecision *decision,
- WebKitPolicyDecisionType type,
- gpointer user_data);
-static void view_resource_request (WebKitWebView *view,
- WebKitWebFrame *frame,
- WebKitWebResource *resource,
- WebKitNetworkRequest *request,
- WebKitNetworkResponse *response,
- gpointer user_data);
-static void view_document_loaded (WebKitWebView *view,
- WebKitWebFrame *frame,
- gpointer user_data);
-
-static void view_print_action (GAction *action,
- GVariant *parameter,
- YelpView *view);
-static void view_history_action (GAction *action,
- GVariant *parameter,
- YelpView *view);
-static void view_navigation_action (GAction *action,
- GVariant *parameter,
- YelpView *view);
-
-static void view_clear_load (YelpView *view);
-static void view_load_page (YelpView *view);
-static void view_show_error_page (YelpView *view,
- GError *error);
-
-static void settings_set_fonts (YelpSettings *settings);
-static void settings_show_text_cursor (YelpSettings *settings);
-
-static void uri_resolved (YelpUri *uri,
- YelpView *view);
-static void document_callback (YelpDocument *document,
- YelpDocumentSignal signal,
- YelpView *view,
- GError *error);
-static void gtk_xft_dpi_changed (GtkSettings *gtk_settings,
- GParamSpec *pspec,
- gpointer user_data);
-static void yelp_view_register_extensions (void);
+#include "yelp-uri-builder.h"
+
+static void yelp_view_dispose (GObject *object);
+static void yelp_view_finalize (GObject *object);
+static void yelp_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void yelp_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static gboolean view_external_uri (YelpView *view,
+ YelpUri *uri);
+static void view_install_uri (YelpView *view,
+ const gchar *uri);
+static void view_scrolled (GtkAdjustment *adjustment,
+ YelpView *view);
+static void view_set_hadjustment (YelpView *view,
+ GParamSpec *pspec,
+ gpointer data);
+static void view_set_vadjustment (YelpView *view,
+ GParamSpec *pspec,
+ gpointer data);
+static void popup_open_link (GtkAction *action,
+ YelpView *view);
+static void popup_open_link_new (GtkAction *action,
+ YelpView *view);
+static void popup_copy_link (GtkAction *action,
+ YelpView *view);
+static void popup_save_image (GtkAction *action,
+ YelpView *view);
+static void popup_send_image (GtkAction *action,
+ YelpView *view);
+static void popup_copy_code (GtkAction *action,
+ YelpView *view);
+static void popup_save_code (GtkAction *action,
+ YelpView *view);
+static void popup_copy_clipboard (GtkAction *action,
+ YelpView *view);
+static gboolean view_populate_context_menu (YelpView *view,
+ WebKitContextMenu *context_menu,
+ GdkEvent *event,
+ WebKitHitTestResult *hit_test_result,
+ gpointer user_data);
+static gboolean view_script_dialog (YelpView *view,
+ WebKitScriptDialog *dialog,
+ gpointer data);
+static gboolean view_policy_decision_requested (YelpView *view,
+ WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType type,
+ gpointer user_data);
+static void view_print_action (GAction *action,
+ GVariant *parameter,
+ YelpView *view);
+static void view_history_action (GAction *action,
+ GVariant *parameter,
+ YelpView *view);
+static void view_navigation_action (GAction *action,
+ GVariant *parameter,
+ YelpView *view);
+
+static void view_clear_load (YelpView *view);
+static void view_load_page (YelpView *view);
+static void view_show_error_page (YelpView *view,
+ GError *error);
+
+static void settings_set_fonts (YelpSettings *settings);
+static void settings_show_text_cursor (YelpSettings *settings);
+
+static void uri_resolved (YelpUri *uri,
+ YelpView *view);
+static void yelp_view_register_custom_schemes (void);
+static void view_load_failed (WebKitWebView *web_view,
+ WebKitLoadEvent load_event,
+ gchar *failing_uri,
+ GError *error,
+ gpointer user_data);
+static void view_load_status_changed (WebKitWebView *view,
+ WebKitLoadEvent load_event,
+ gpointer user_data);
+static void gtk_xft_dpi_changed (GtkSettings *gtk_settings,
+ GParamSpec *pspec,
+ gpointer user_data);
+static void yelp_view_register_extensions (void);
static gchar *nautilus_sendto = NULL;
@@ -192,12 +186,37 @@ back_entry_free (YelpBackEntry *back)
g_free (back);
}
+typedef struct _RequestAsyncData RequestAsyncData;
+struct _RequestAsyncData {
+ WebKitURISchemeRequest *request;
+ GFile *resource_file;
+ gchar *page_id;
+};
+
+static RequestAsyncData *
+request_async_data_new (WebKitURISchemeRequest *request, gchar *page_id)
+{
+ RequestAsyncData *data;
+
+ data = g_slice_new (RequestAsyncData);
+ data->request = g_object_ref (request);
+ data->page_id = g_strdup (page_id);
+ return data;
+}
+
+static void
+request_async_data_free (RequestAsyncData *data)
+{
+ g_object_unref (data->request);
+ g_clear_pointer (&data->page_id, g_free);
+ g_slice_free (RequestAsyncData, data);
+}
+
typedef struct _YelpViewPrivate YelpViewPrivate;
struct _YelpViewPrivate {
YelpUri *uri;
YelpUri *resolve_uri;
gulong uri_resolved;
- gchar *bogus_uri;
YelpDocument *document;
GtkSettings *gtk_settings;
gulong gtk_xft_dpi_changed;
@@ -322,10 +341,10 @@ yelp_view_init (YelpView *view)
priv->navigation_requested =
g_signal_connect (view, "decide-policy",
G_CALLBACK (view_policy_decision_requested), NULL);
- g_signal_connect (view, "resource-request-starting",
- G_CALLBACK (view_resource_request), NULL);
- g_signal_connect (view, "document-load-finished",
- G_CALLBACK (view_document_loaded), NULL);
+ g_signal_connect (view, "load-changed",
+ G_CALLBACK (view_load_status_changed), NULL);
+ g_signal_connect (view, "load-failed",
+ G_CALLBACK (view_load_failed), NULL);
g_signal_connect (view, "notify::hadjustment",
G_CALLBACK (view_set_hadjustment), NULL);
g_signal_connect (view, "notify::vadjustment",
@@ -457,7 +476,6 @@ yelp_view_finalize (GObject *object)
g_free (priv->page_desc);
g_free (priv->page_icon);
- g_free (priv->bogus_uri);
g_object_unref (priv->popup_actions);
G_OBJECT_CLASS (yelp_view_parent_class)->finalize (object);
@@ -473,7 +491,6 @@ yelp_view_class_init (YelpViewClass *klass)
websettings = webkit_settings_new_with_settings (
"default-charset", "utf-8",
- "enable-private-browsing", TRUE,
NULL);
g_signal_connect (settings,
@@ -488,6 +505,7 @@ yelp_view_class_init (YelpViewClass *klass)
settings_show_text_cursor (settings);
yelp_view_register_extensions ();
+ yelp_view_register_custom_schemes ();
klass->external_uri = view_external_uri;
@@ -749,6 +767,141 @@ yelp_view_register_actions (YelpView *view,
/******************************************************************************/
+static void
+document_callback (YelpDocument *document,
+ YelpDocumentSignal signal,
+ RequestAsyncData *data,
+ GError *error)
+{
+ const gchar *contents;
+ gchar *mime_type;
+ GInputStream *stream;
+ int content_length;
+
+ if (signal == YELP_DOCUMENT_SIGNAL_INFO)
+ return;
+
+ if (signal == YELP_DOCUMENT_SIGNAL_ERROR) {
+ webkit_uri_scheme_request_finish_error (data->request, error);
+ return;
+ }
+
+ mime_type = yelp_document_get_mime_type (document, data->page_id);
+
+ contents = yelp_document_read_contents (document, data->page_id);
+
+ content_length = strlen (contents);
+
+ stream = g_memory_input_stream_new_from_data (g_strdup (contents), content_length, g_free);
+ yelp_document_finish_read (document, contents);
+
+ webkit_uri_scheme_request_finish (data->request,
+ stream,
+ content_length,
+ mime_type);
+ request_async_data_free (data);
+ g_free (mime_type);
+ g_object_unref (stream);
+}
+
+static void
+help_cb_uri_resolved (YelpUri *uri,
+ WebKitURISchemeRequest *request)
+{
+ YelpDocument *document;
+
+ if ((document = yelp_document_get_for_uri (uri))) {
+ RequestAsyncData *data;
+ gchar * page_id;
+
+ page_id = yelp_uri_get_page_id (uri);
+ data = request_async_data_new (request, page_id);
+ g_free (page_id);
+
+ yelp_document_request_page (document,
+ data->page_id,
+ NULL,
+ (YelpDocumentCallback) document_callback,
+ data);
+ g_object_unref (document);
+
+ } else {
+ YelpUriDocumentType doctype;
+ GError *error;
+ gchar *struri;
+
+ doctype = yelp_uri_get_document_type (uri);
+ if (doctype == YELP_URI_DOCUMENT_TYPE_NOT_FOUND) {
+ struri = yelp_uri_get_canonical_uri (uri);
+ if (struri) {
+ error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+ _("The URI ‘%s’ does not point to a valid page."),
+ struri);
+ g_free (struri);
+ }
+ else {
+ error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
+ _("The URI does not point to a valid page."));
+ }
+ } else if (doctype == YELP_URI_DOCUMENT_TYPE_ERROR) {
+ struri = yelp_uri_get_canonical_uri (uri);
+ error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
+ _("The URI ‘%s’ could not be parsed."),
+ struri);
+ g_free (struri);
+ } else {
+ error = g_error_new (YELP_ERROR, YELP_ERROR_UNKNOWN,
+ _("Unknown Error."));
+ }
+
+ webkit_uri_scheme_request_finish_error (request, error);
+ g_object_unref (error);
+ }
+}
+
+static void
+help_uri_scheme_request_cb (WebKitURISchemeRequest *request,
+ gpointer user_data)
+{
+ YelpUri *uri;
+ gchar *uri_str;
+
+ uri_str = build_yelp_uri (webkit_uri_scheme_request_get_uri (request));
+
+ uri = yelp_uri_new (uri_str);
+ g_free (uri_str);
+
+ g_signal_connect (uri, "resolved", G_CALLBACK (help_cb_uri_resolved), request);
+ yelp_uri_resolve (uri);
+
+ g_object_unref (uri);
+}
+
+static const gchar *help_schemes[] = { "help", "ghelp", "gnome-help", "help-list", "info", "man", NULL };
+
+static void
+yelp_view_register_custom_schemes (void)
+{
+ WebKitWebContext *context = webkit_web_context_get_default ();
+ WebKitSecurityManager *sec_manager = webkit_web_context_get_security_manager (context);
+ gint i;
+ gchar *network_scheme;
+
+ for (i = 0; help_schemes[i] != NULL; i++) {
+ network_scheme = build_network_scheme (help_schemes[i]);
+
+ webkit_web_context_register_uri_scheme (context, network_scheme,
+ (WebKitURISchemeRequestCallback) help_uri_scheme_request_cb,
+ NULL, NULL);
+
+ webkit_security_manager_register_uri_scheme_as_local (sec_manager, network_scheme);
+
+ g_free (network_scheme);
+ }
+}
+
+/******************************************************************************/
+
void
yelp_view_add_link_action (YelpView *view,
GtkAction *action,
@@ -772,10 +925,7 @@ yelp_view_get_active_link_uri (YelpView *view)
YelpViewPrivate *priv = GET_PRIV (view);
YelpUri *uri;
- if (g_str_has_prefix (priv->popup_link_uri, BOGUS_URI))
- uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri + BOGUS_URI_LEN);
- else
- uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
+ uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
return uri;
}
@@ -1054,10 +1204,7 @@ popup_open_link (GtkAction *action,
YelpViewPrivate *priv = GET_PRIV (view);
YelpUri *uri;
- if (g_str_has_prefix (priv->popup_link_uri, BOGUS_URI))
- uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri + BOGUS_URI_LEN);
- else
- uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
+ uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
yelp_view_load_uri (view, uri);
g_object_unref (uri);
@@ -1076,10 +1223,7 @@ popup_open_link_new (GtkAction *action,
YelpViewPrivate *priv = GET_PRIV (view);
YelpUri *uri;
- if (g_str_has_prefix (priv->popup_link_uri, BOGUS_URI))
- uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri + BOGUS_URI_LEN);
- else
- uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
+ uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
g_free (priv->popup_link_uri);
priv->popup_link_uri = NULL;
@@ -1332,10 +1476,10 @@ view_populate_context_menu (YelpView *view,
g_variant_dict_init (&dom_info_dict, dom_info_variant);
if (webkit_hit_test_result_context_is_link (hit_test_result)) {
- gchar *uri;
- uri = webkit_hit_test_result_get_link_uri (hit_test_result);
+ const gchar *uri = webkit_hit_test_result_get_link_uri (hit_test_result);
g_free (priv->popup_link_uri);
- priv->popup_link_uri = uri;
+
+ priv->popup_link_uri = build_yelp_uri (uri);
g_clear_pointer (&priv->popup_link_text, g_free);
if (dom_info_variant)
@@ -1418,15 +1562,32 @@ view_populate_context_menu (YelpView *view,
gboolean image = webkit_hit_test_result_context_is_image (hit_test_result);
const gchar *uri = image ? webkit_hit_test_result_get_image_uri (hit_test_result) :
webkit_hit_test_result_get_media_uri (hit_test_result);
+ gchar *yelp_uri;
g_free (priv->popup_image_uri);
- if (g_str_has_prefix (uri, BOGUS_URI)) {
- priv->popup_image_uri = yelp_uri_locate_file_uri (priv->uri, uri + BOGUS_URI_LEN);
- g_free (uri);
+
+ yelp_uri = build_yelp_uri (uri);
+
+ if (g_str_has_prefix (yelp_uri, "help:") ||
+ g_str_has_prefix (yelp_uri, "ghelp:") ||
+ g_str_has_prefix (yelp_uri, "gnome-help:")) {
+ gchar *image_uri = strstr (yelp_uri, "/");
+
+ if (image_uri) {
+ image_uri[0] = '\0';
+ image_uri++;
+ }
+
+ if (image_uri && image_uri[0] != '\0')
+ priv->popup_image_uri = yelp_uri_locate_file_uri (priv->uri, image_uri);
+ else
+ priv->popup_image_uri = NULL;
}
else {
- priv->popup_image_uri = uri;
+ priv->popup_image_uri = yelp_uri;
}
+ g_free (yelp_uri);
+
item = webkit_context_menu_item_new_separator ();
webkit_context_menu_append (context_menu, item);
@@ -1508,100 +1669,148 @@ view_policy_decision_requested (YelpView *view,
WebKitPolicyDecisionType type,
gpointer user_data)
{
- if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
- return FALSE;
-
YelpViewPrivate *priv = GET_PRIV (view);
WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
WebKitURIRequest *request = webkit_navigation_policy_decision_get_request (navigation_decision);
const gchar *requri = webkit_uri_request_get_uri (request);
+ gchar *fixed_uri;
YelpUri *uri;
- if (priv->bogus_uri &&
- g_str_has_prefix (requri, priv->bogus_uri) &&
- requri[strlen(priv->bogus_uri)] == '#') {
- gchar *tmp = g_strconcat("xref:", requri + strlen(priv->bogus_uri), NULL);
- uri = yelp_uri_new_relative (priv->uri, tmp);
- g_free (tmp);
- }
- else if (g_str_has_prefix (requri, BOGUS_URI)) {
- uri = yelp_uri_new_relative (priv->uri, requri + BOGUS_URI_LEN);
- }
- else
- uri = yelp_uri_new_relative (priv->uri, requri);
+ if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
+ return FALSE;
+
+ fixed_uri = build_yelp_uri (requri);
webkit_policy_decision_ignore (decision);
+ uri = yelp_uri_new_relative (priv->uri, fixed_uri);
yelp_view_load_uri ((YelpView *) view, uri);
g_object_unref (uri);
+ g_free (fixed_uri);
return TRUE;
}
static void
-view_resource_request (WebKitWebView *view,
- WebKitWebFrame *frame,
- WebKitWebResource *resource,
- WebKitNetworkRequest *request,
- WebKitNetworkResponse *response,
- gpointer user_data)
+view_load_status_changed (WebKitWebView *view,
+ WebKitLoadEvent load_event,
+ gpointer user_data)
{
YelpViewPrivate *priv = GET_PRIV (view);
- const gchar *requri = webkit_network_request_get_uri (request);
- gchar *newpath;
- if (!g_str_has_prefix (requri, BOGUS_URI))
+ if (priv->state == YELP_VIEW_STATE_ERROR)
return;
- /* We get this signal for the page itself. Ignore. */
- if (g_str_equal (requri, priv->bogus_uri))
- return;
+ switch (load_event) {
+ case WEBKIT_LOAD_COMMITTED: {
+ gchar *real_id;
+ YelpBackEntry *back = NULL;
+ GParamSpec *spec;
+
+ real_id = yelp_document_get_page_id (priv->document, priv->page_id);
+ if (priv->page_id && real_id && g_str_equal (real_id, priv->page_id)) {
+ g_free (real_id);
+ }
+ else {
+ g_free (priv->page_id);
+ priv->page_id = real_id;
+ spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
+ "page-id");
+ g_signal_emit_by_name (view, "notify::page-id", spec);
+ }
+
+ g_free (priv->root_title);
+ g_free (priv->page_title);
+ g_free (priv->page_desc);
+ g_free (priv->page_icon);
+
+ priv->root_title = yelp_document_get_root_title (priv->document, priv->page_id);
+ priv->page_title = yelp_document_get_page_title (priv->document, priv->page_id);
+ priv->page_desc = yelp_document_get_page_desc (priv->document, priv->page_id);
+ priv->page_icon = yelp_document_get_page_icon (priv->document, priv->page_id);
- newpath = yelp_uri_locate_file_uri (priv->uri, requri + BOGUS_URI_LEN);
- if (newpath != NULL) {
- webkit_network_request_set_uri (request, newpath);
- g_free (newpath);
+ if (priv->back_cur)
+ back = priv->back_cur->data;
+ if (back) {
+ g_free (back->title);
+ back->title = g_strdup (priv->page_title);
+ g_free (back->desc);
+ back->desc = g_strdup (priv->page_desc);
+ }
+
+ spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
+ "root-title");
+ g_signal_emit_by_name (view, "notify::root-title", spec);
+
+ spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
+ "page-title");
+ g_signal_emit_by_name (view, "notify::page-title", spec);
+
+ spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
+ "page-desc");
+ g_signal_emit_by_name (view, "notify::page-desc", spec);
+
+ spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
+ "page-icon");
+ g_signal_emit_by_name (view, "notify::page-icon", spec);
+ break;
}
- else {
- webkit_network_request_set_uri (request, "about:blank");
+ case WEBKIT_LOAD_FINISHED:
+
+ g_signal_handler_unblock (view, priv->navigation_requested);
+
+ g_object_set (view, "state", YELP_VIEW_STATE_LOADED, NULL);
+
+ /* Setting adjustments only work after the page is loaded. These
+ * are set by view_history_action, and they're reset to 0 after
+ * each load here.
+ */
+ if (priv->vadjust > 0) {
+ if (priv->vadjustment)
+ gtk_adjustment_set_value (priv->vadjustment, priv->vadjust);
+ priv->vadjust = 0;
+ }
+ if (priv->hadjust > 0) {
+ if (priv->hadjustment)
+ gtk_adjustment_set_value (priv->hadjustment, priv->hadjust);
+ priv->hadjust = 0;
+ }
+
+ /* If the document didn't give us a page title, get it from WebKit.
+ * We let the main loop run through so that WebKit gets the title
+ * set so that we can send notify::page-title before loaded. It
+ * simplifies things if YelpView consumers can assume the title
+ * is set before loaded is triggered.
+ */
+ if (priv->page_title == NULL) {
+ GParamSpec *spec;
+ priv->page_title = g_strdup (webkit_web_view_get_title (view));
+ spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
+ "page-title");
+ g_signal_emit_by_name (view, "notify::page-title", spec);
+ }
+
+ g_signal_emit (view, signals[LOADED], 0);
+
+ break;
+ case WEBKIT_LOAD_STARTED:
+ case WEBKIT_LOAD_REDIRECTED:
+ default:
+ break;
}
}
static void
-view_document_loaded (WebKitWebView *view,
- WebKitWebFrame *frame,
- gpointer user_data)
+view_load_failed (WebKitWebView *view,
+ WebKitLoadEvent load_event,
+ gchar *failing_uri,
+ GError *error,
+ gpointer user_data)
{
YelpViewPrivate *priv = GET_PRIV (view);
- gchar *search_terms;
-
- search_terms = yelp_uri_get_query (priv->uri, "terms");
-
- if (search_terms) {
- WebKitDOMDocument *doc;
- WebKitDOMElement *body, *link;
- doc = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_query_selector (doc, "div.body", NULL);
- if (body) {
- gchar *tmp, *uri, *txt;
- link = webkit_dom_document_create_element (doc, "a", NULL);
- webkit_dom_element_set_attribute (link, "class", "fullsearch", NULL);
- tmp = g_uri_escape_string (search_terms, NULL, FALSE);
- uri = g_strconcat ("xref:search=", tmp, NULL);
- webkit_dom_element_set_attribute (link, "href", uri, NULL);
- g_free (tmp);
- g_free (uri);
- txt = g_strdup_printf (_("See all search results for “%s”"),
- search_terms);
- webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (link), txt, NULL);
- g_free (txt);
- webkit_dom_node_insert_before (WEBKIT_DOM_NODE (body),
- WEBKIT_DOM_NODE (link),
- webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)),
- NULL);
- }
- g_free (search_terms);
- }
+
+ g_signal_handler_unblock (view, priv->navigation_requested);
+ view_show_error_page (YELP_VIEW (view), error);
}
static void
@@ -1636,6 +1845,8 @@ view_history_action (GAction *action,
GList *newcur;
YelpViewPrivate *priv = GET_PRIV (view);
+ g_signal_handler_unblock (view, priv->navigation_requested);
+
if (priv->back_cur == NULL)
return;
@@ -1667,6 +1878,8 @@ view_navigation_action (GAction *action,
gchar *page_id, *new_id, *xref;
YelpUri *new_uri;
+ g_signal_handler_unblock (view, priv->navigation_requested);
+
page_id = yelp_uri_get_page_id (priv->uri);
if (g_str_equal (g_action_get_name (action), "yelp-view-go-previous"))
@@ -1718,7 +1931,7 @@ static void
view_load_page (YelpView *view)
{
YelpViewPrivate *priv = GET_PRIV (view);
- gchar *page_id;
+ gchar *uri_str;
g_return_if_fail (priv->cancellable == NULL);
@@ -1743,14 +1956,12 @@ view_load_page (YelpView *view)
return;
}
- page_id = yelp_uri_get_page_id (priv->uri);
- priv->cancellable = g_cancellable_new ();
- yelp_document_request_page (priv->document,
- page_id,
- priv->cancellable,
- (YelpDocumentCallback) document_callback,
- view);
- g_free (page_id);
+ uri_str = build_network_uri (priv->uri, priv->document);
+
+ g_signal_handler_block (view, priv->navigation_requested);
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), uri_str);
+
+ g_free (uri_str);
}
#define FORMAT_ERRORPAGE \
@@ -1804,7 +2015,7 @@ view_show_error_page (YelpView *view,
gint iconsize;
GParamSpec *spec;
gboolean doc404 = FALSE;
- const gchar *left = (gtk_widget_get_direction((GtkWidget *) view) == GTK_TEXT_DIR_RTL) ? "right" : "left";
+ const gchar *left = (gtk_widget_get_direction ((GtkWidget *) view) == GTK_TEXT_DIR_RTL) ? "right" : "left";
if (priv->uri && yelp_uri_get_document_type (priv->uri) == YELP_URI_DOCUMENT_TYPE_NOT_FOUND)
doc404 = TRUE;
@@ -1898,18 +2109,15 @@ view_show_error_page (YelpView *view,
g_signal_emit_by_name (view, "notify::page-icon", spec);
g_signal_emit (view, signals[LOADED], 0);
+
g_signal_handler_block (view, priv->navigation_requested);
- webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
- page,
- "text/html",
- "UTF-8",
- "file:///error/");
- g_signal_handler_unblock (view, priv->navigation_requested);
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (view),
+ page,
+ "file:///error/");
g_free (title_m);
g_free (content_beg);
if (content_end != NULL)
g_free (content_end);
- g_free (page);
}
static gint
@@ -2092,192 +2300,20 @@ uri_resolved (YelpUri *uri,
"page-icon");
g_signal_emit_by_name (view, "notify::page-icon", spec);
- if (error == NULL)
- view_load_page (view);
- else {
- view_show_error_page (view, error);
- g_error_free (error);
- }
-}
-
-static void
-document_callback (YelpDocument *document,
- YelpDocumentSignal signal,
- YelpView *view,
- GError *error)
-{
- YelpViewPrivate *priv = GET_PRIV (view);
-
- if (signal == YELP_DOCUMENT_SIGNAL_INFO) {
- gchar *prev_id, *next_id, *real_id;
- YelpBackEntry *back = NULL;
- GParamSpec *spec;
-
- real_id = yelp_document_get_page_id (document, priv->page_id);
- if (priv->page_id && real_id && g_str_equal (real_id, priv->page_id)) {
- g_free (real_id);
- }
- else {
- g_free (priv->page_id);
- priv->page_id = real_id;
- spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
- "page-id");
- g_signal_emit_by_name (view, "notify::page-id", spec);
- }
-
- g_free (priv->root_title);
- g_free (priv->page_title);
- g_free (priv->page_desc);
- g_free (priv->page_icon);
-
- priv->root_title = yelp_document_get_root_title (document, priv->page_id);
- priv->page_title = yelp_document_get_page_title (document, priv->page_id);
- priv->page_desc = yelp_document_get_page_desc (document, priv->page_id);
- priv->page_icon = yelp_document_get_page_icon (document, priv->page_id);
-
- if (priv->back_cur)
- back = priv->back_cur->data;
- if (back) {
- g_free (back->title);
- back->title = g_strdup (priv->page_title);
- g_free (back->desc);
- back->desc = g_strdup (priv->page_desc);
- }
-
- prev_id = yelp_document_get_prev_id (document, priv->page_id);
- g_simple_action_set_enabled (priv->prev_action, prev_id != NULL);
- g_free (prev_id);
-
- next_id = yelp_document_get_next_id (document, priv->page_id);
- g_simple_action_set_enabled (priv->next_action, next_id != NULL);
- g_free (next_id);
-
- spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
- "root-title");
- g_signal_emit_by_name (view, "notify::root-title", spec);
-
- spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
- "page-title");
- g_signal_emit_by_name (view, "notify::page-title", spec);
-
- spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
- "page-desc");
- g_signal_emit_by_name (view, "notify::page-desc", spec);
-
- spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
- "page-icon");
- g_signal_emit_by_name (view, "notify::page-icon", spec);
- }
- else if (signal == YELP_DOCUMENT_SIGNAL_CONTENTS) {
- YelpUriDocumentType doctype;
- const gchar *contents;
- gchar *mime_type, *page_id, *frag_id, *full_uri;
- page_id = yelp_uri_get_page_id (priv->uri);
- mime_type = yelp_document_get_mime_type (document, page_id);
- contents = yelp_document_read_contents (document, page_id);
- frag_id = yelp_uri_get_frag_id (priv->uri);
- g_free (priv->bogus_uri);
- /* We don't have actual page and frag IDs for DocBook. We just map IDs
- of block elements. The result is that we get xref:someid#someid.
- If someid is really the page ID, we just drop the frag reference.
- Otherwise, normal page views scroll past the link trail.
- */
- if (frag_id != NULL) {
- if (YELP_IS_DOCBOOK_DOCUMENT (document)) {
- gchar *real_id = yelp_document_get_page_id (document, page_id);
- if (g_str_equal (real_id, frag_id)) {
- g_free (frag_id);
- frag_id = NULL;
- }
- g_free (real_id);
- }
- }
- /* We have to give WebKit a URI in a scheme it understands, otherwise we
- won't get the resource-request-starting signal. So we can't use the
- canonical URI, because it might be something like ghelp. We also have
- to give it something unique, because WebKit ignores our load_string
- call if the URI isn't different. We could try to construct something
- based on actual file locations, but in fact it doesn't matter. So
- we just make a bogus URI that's easy to process later.
- */
- doctype = yelp_uri_get_document_type (priv->uri);
- full_uri = yelp_uri_get_canonical_uri (priv->uri);
- if (g_str_has_prefix (full_uri, "file:/") &&
- (doctype == YELP_URI_DOCUMENT_TYPE_TEXT ||
- doctype == YELP_URI_DOCUMENT_TYPE_HTML ||
- doctype == YELP_URI_DOCUMENT_TYPE_XHTML )) {
- priv->bogus_uri = full_uri;
- }
- else {
- g_free (full_uri);
- if (frag_id != NULL)
- priv->bogus_uri = g_strdup_printf ("%s%p#%s", BOGUS_URI, priv->uri, frag_id);
- else
- priv->bogus_uri = g_strdup_printf ("%s%p", BOGUS_URI, priv->uri);
- }
- g_signal_handler_block (view, priv->navigation_requested);
- webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
- contents,
- mime_type,
- "UTF-8",
- priv->bogus_uri);
- g_signal_handler_unblock (view, priv->navigation_requested);
- g_object_set (view, "state", YELP_VIEW_STATE_LOADED, NULL);
-
- /* If we need to set the GtkAdjustment or trigger the page title
- * from what WebKit thinks it is (see comment below), we need to
- * let the main loop run through.
- */
- if (priv->vadjust > 0 || priv->hadjust > 0 || priv->page_title == NULL)
- while (g_main_context_pending (NULL)) {
- WebKitLoadStatus status;
- status = webkit_web_view_get_load_status (WEBKIT_WEB_VIEW (view));
- g_main_context_iteration (NULL, FALSE);
- /* Sometimes some runaway JavaScript causes there to always
- * be pending sources. Break out if the document is loaded.
- */
- if (status == WEBKIT_LOAD_FINISHED ||
- status == WEBKIT_LOAD_FAILED)
- break;
- }
-
- /* Setting adjustments only work after the page is loaded. These
- * are set by view_history_action, and they're reset to 0 after
- * each load here.
- */
- if (priv->vadjust > 0) {
- if (priv->vadjustment)
- gtk_adjustment_set_value (priv->vadjustment, priv->vadjust);
- priv->vadjust = 0;
- }
- if (priv->hadjust > 0) {
- if (priv->hadjustment)
- gtk_adjustment_set_value (priv->hadjustment, priv->hadjust);
- priv->hadjust = 0;
- }
+ if (error == NULL) {
+ document = yelp_document_get_for_uri (uri);
+ if (priv->document)
+ g_object_unref (priv->document);
+ priv->document = document;
- /* If the document didn't give us a page title, get it from WebKit.
- * We let the main loop run through so that WebKit gets the title
- * set so that we can send notify::page-title before loaded. It
- * simplifies things if YelpView consumers can assume the title
- * is set before loaded is triggered.
- */
- if (priv->page_title == NULL) {
- GParamSpec *spec;
- priv->page_title = g_strdup (webkit_web_view_get_title (WEBKIT_WEB_VIEW (view)));
- spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
- "page-title");
- g_signal_emit_by_name (view, "notify::page-title", spec);
+ view_load_page (view);
+ } else {
+ if (priv->document != NULL) {
+ g_object_unref (priv->document);
+ priv->document = NULL;
}
-
- g_free (frag_id);
- g_free (page_id);
- g_free (mime_type);
- yelp_document_finish_read (document, contents);
- g_signal_emit (view, signals[LOADED], 0);
- }
- else if (signal == YELP_DOCUMENT_SIGNAL_ERROR) {
view_show_error_page (view, error);
+ g_error_free (error);
}
}
diff --git a/libyelp/yelp-view.h b/libyelp/yelp-view.h
index 3e9ac1dd..c28e131d 100644
--- a/libyelp/yelp-view.h
+++ b/libyelp/yelp-view.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
+ * Copyright (C) 2014 Igalia S.L.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -36,8 +37,8 @@ G_BEGIN_DECLS
#define YELP_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), YELP_TYPE_VIEW))
#define YELP_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), YELP_TYPE_VIEW, YelpViewClass))
-typedef struct _YelpView YelpView;
-typedef struct _YelpViewClass YelpViewClass;
+typedef struct _YelpView YelpView;
+typedef struct _YelpViewClass YelpViewClass;
typedef gboolean (* YelpViewActionValidFunc) (YelpView *view, GtkAction *action, gchar *uri, gpointer data);
struct _YelpView