Update Chinese (China) translation
[yelp.git] / libyelp / yelp-view.c
blob183506e413f077ff16ed7a7776afd32ee29fc98a
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
4 * Copyright (C) 2014 Igalia S.L.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 * Author: Shaun McCance <shaunm@gnome.org>
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <glib/gi18n.h>
27 #include <glib-object.h>
28 #include <gio/gio.h>
29 #include <gtk/gtk.h>
30 #ifdef GDK_WINDOWING_X11
31 #include <gdk/gdkx.h>
32 #endif
33 #include <math.h>
34 #include <webkit2/webkit2.h>
36 #include "yelp-debug.h"
37 #include "yelp-docbook-document.h"
38 #include "yelp-error.h"
39 #include "yelp-marshal.h"
40 #include "yelp-settings.h"
41 #include "yelp-types.h"
42 #include "yelp-view.h"
43 #include "yelp-uri-builder.h"
45 static void yelp_view_dispose (GObject *object);
46 static void yelp_view_finalize (GObject *object);
47 static void yelp_view_get_property (GObject *object,
48 guint prop_id,
49 GValue *value,
50 GParamSpec *pspec);
51 static void yelp_view_set_property (GObject *object,
52 guint prop_id,
53 const GValue *value,
54 GParamSpec *pspec);
55 static void yelp_view_resolve_uri (YelpView *view,
56 YelpUri *uri);
58 static gboolean view_external_uri (YelpView *view,
59 YelpUri *uri);
60 static void view_install_uri (YelpView *view,
61 const gchar *uri);
62 static void popup_open_link (GtkAction *action,
63 YelpView *view);
64 static void popup_open_link_new (GtkAction *action,
65 YelpView *view);
66 static void popup_copy_link (GtkAction *action,
67 YelpView *view);
68 static void popup_save_image (GtkAction *action,
69 YelpView *view);
70 static void popup_send_image (GtkAction *action,
71 YelpView *view);
72 static void popup_copy_code (GtkAction *action,
73 YelpView *view);
74 static void popup_save_code (GtkAction *action,
75 YelpView *view);
76 static void popup_copy_clipboard (GtkAction *action,
77 YelpView *view);
78 static gboolean view_populate_context_menu (YelpView *view,
79 WebKitContextMenu *context_menu,
80 GdkEvent *event,
81 WebKitHitTestResult *hit_test_result,
82 gpointer user_data);
83 static gboolean view_script_dialog (YelpView *view,
84 WebKitScriptDialog *dialog,
85 gpointer data);
86 static gboolean view_policy_decision_requested (YelpView *view,
87 WebKitPolicyDecision *decision,
88 WebKitPolicyDecisionType type,
89 gpointer user_data);
90 static void view_print_action (GAction *action,
91 GVariant *parameter,
92 YelpView *view);
93 static void view_history_action (GAction *action,
94 GVariant *parameter,
95 YelpView *view);
96 static void view_history_changed (YelpView *view);
97 static void view_navigation_action (GAction *action,
98 GVariant *parameter,
99 YelpView *view);
101 static void view_clear_load (YelpView *view);
102 static void view_load_page (YelpView *view);
103 static void view_show_error_page (YelpView *view,
104 GError *error);
106 static void settings_set_fonts (YelpSettings *settings,
107 gpointer user_data);
108 static void settings_show_text_cursor (YelpSettings *settings);
110 static void uri_resolved (YelpUri *uri,
111 YelpView *view);
112 static void yelp_view_register_custom_schemes (void);
113 static void view_load_failed (WebKitWebView *web_view,
114 WebKitLoadEvent load_event,
115 gchar *failing_uri,
116 GError *error,
117 gpointer user_data);
118 static void view_load_status_changed (WebKitWebView *view,
119 WebKitLoadEvent load_event,
120 gpointer user_data);
121 static void yelp_view_register_extensions (void);
123 static gchar *nautilus_sendto = NULL;
125 enum {
126 PROP_0,
127 PROP_URI,
128 PROP_STATE,
129 PROP_PAGE_ID,
130 PROP_ROOT_TITLE,
131 PROP_PAGE_TITLE,
132 PROP_PAGE_DESC,
133 PROP_PAGE_ICON
136 enum {
137 NEW_VIEW_REQUESTED,
138 EXTERNAL_URI,
139 LOADED,
140 LAST_SIGNAL
142 static gint signals[LAST_SIGNAL] = { 0 };
144 G_DEFINE_TYPE (YelpView, yelp_view, WEBKIT_TYPE_WEB_VIEW)
145 #define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_VIEW, YelpViewPrivate))
147 static WebKitSettings *
148 yelp_view_get_global_settings (void)
150 static WebKitSettings *websettings = NULL;
152 if (!websettings)
153 websettings = webkit_settings_new_with_settings ("default-charset", "utf-8", NULL);
155 return websettings;
158 typedef struct _YelpActionEntry YelpActionEntry;
159 struct _YelpActionEntry {
160 GtkAction *action;
161 YelpViewActionValidFunc func;
162 gpointer data;
164 static void
165 action_entry_free (YelpActionEntry *entry)
167 if (entry == NULL)
168 return;
169 g_object_unref (entry->action);
170 g_free (entry);
173 typedef struct _RequestAsyncData RequestAsyncData;
174 struct _RequestAsyncData {
175 WebKitURISchemeRequest *request;
176 GFile *resource_file;
177 gchar *page_id;
180 static RequestAsyncData *
181 request_async_data_new (WebKitURISchemeRequest *request, gchar *page_id)
183 RequestAsyncData *data;
185 data = g_slice_new0 (RequestAsyncData);
186 data->request = g_object_ref (request);
187 data->page_id = g_strdup (page_id);
188 return data;
191 static void
192 request_async_data_free (RequestAsyncData *data)
194 g_object_unref (data->request);
195 g_clear_pointer (&data->page_id, g_free);
196 g_slice_free (RequestAsyncData, data);
199 typedef struct _YelpViewPrivate YelpViewPrivate;
200 struct _YelpViewPrivate {
201 YelpUri *uri;
202 YelpUri *resolve_uri;
203 gulong uri_resolved;
204 YelpDocument *document;
205 GCancellable *cancellable;
206 gulong fonts_changed;
208 gchar *popup_link_uri;
209 gchar *popup_link_text;
210 gchar *popup_image_uri;
211 gchar *popup_code_text;
212 gchar *popup_code_title;
214 YelpViewState state;
215 YelpViewState prevstate;
217 gchar *page_id;
218 gchar *root_title;
219 gchar *page_title;
220 gchar *page_desc;
221 gchar *page_icon;
223 GSimpleAction *print_action;
224 GSimpleAction *back_action;
225 GSimpleAction *forward_action;
226 GSimpleAction *prev_action;
227 GSimpleAction *next_action;
229 GtkActionGroup *popup_actions;
231 GSList *link_actions;
233 gboolean resolve_uri_on_policy_decision;
234 gboolean load_page_after_resolved;
237 #define TARGET_TYPE_URI_LIST "text/uri-list"
238 enum {
239 TARGET_URI_LIST
242 static void
243 yelp_view_init (YelpView *view)
245 static const GtkActionEntry popup_action_entries[] = {
247 "CopyCode", NULL,
248 N_("C_opy Code Block"), NULL, NULL,
249 G_CALLBACK (popup_copy_code)
252 "CopyLink", NULL,
253 N_("_Copy Link Location"), NULL, NULL,
254 G_CALLBACK (popup_copy_link)
257 "OpenLink", NULL,
258 N_("_Open Link"), NULL, NULL,
259 G_CALLBACK (popup_open_link)
262 "OpenLinkNew", NULL,
263 N_("Open Link in New _Window"), NULL, NULL,
264 G_CALLBACK (popup_open_link_new)
267 "SendEmail", NULL,
268 NULL, NULL, NULL,
269 G_CALLBACK (popup_open_link)
272 "InstallPackages", NULL,
273 N_("_Install Packages"), NULL, NULL,
274 G_CALLBACK (popup_open_link)
277 "SaveCode", NULL,
278 N_("Save Code _Block Asā€¦"), NULL, NULL,
279 G_CALLBACK (popup_save_code)
282 "SaveMedia", NULL,
283 NULL, NULL, NULL,
284 G_CALLBACK (popup_save_image)
287 "SendMedia", NULL,
288 NULL, NULL, NULL,
289 G_CALLBACK (popup_send_image)
292 "CopyText", NULL,
293 N_("_Copy Text"), NULL, NULL,
294 G_CALLBACK (popup_copy_clipboard)
298 YelpViewPrivate *priv = GET_PRIV (view);
300 priv->cancellable = NULL;
302 priv->prevstate = priv->state = YELP_VIEW_STATE_BLANK;
304 priv->resolve_uri_on_policy_decision = TRUE;
305 g_signal_connect (view, "decide-policy",
306 G_CALLBACK (view_policy_decision_requested), NULL);
307 g_signal_connect (view, "load-changed",
308 G_CALLBACK (view_load_status_changed), NULL);
309 g_signal_connect (view, "load-failed",
310 G_CALLBACK (view_load_failed), NULL);
311 g_signal_connect (view, "context-menu",
312 G_CALLBACK (view_populate_context_menu), NULL);
313 g_signal_connect (view, "script-dialog",
314 G_CALLBACK (view_script_dialog), NULL);
316 priv->popup_actions = gtk_action_group_new ("PopupActions");
317 gtk_action_group_add_actions (priv->popup_actions, popup_action_entries,
318 G_N_ELEMENTS (popup_action_entries), view);
320 priv->print_action = g_simple_action_new ("yelp-view-print", NULL);
321 g_signal_connect (priv->print_action,
322 "activate",
323 G_CALLBACK (view_print_action),
324 view);
326 priv->back_action = g_simple_action_new ("yelp-view-go-back", NULL);
327 g_simple_action_set_enabled (priv->back_action, FALSE);
328 g_signal_connect (priv->back_action,
329 "activate",
330 G_CALLBACK (view_history_action),
331 view);
333 priv->forward_action = g_simple_action_new ("yelp-view-go-forward", NULL);
334 g_simple_action_set_enabled (priv->forward_action, FALSE);
335 g_signal_connect (priv->forward_action,
336 "activate",
337 G_CALLBACK (view_history_action),
338 view);
340 priv->prev_action = g_simple_action_new ("yelp-view-go-previous", NULL);
341 g_simple_action_set_enabled (priv->prev_action, FALSE);
342 g_signal_connect (priv->prev_action,
343 "activate",
344 G_CALLBACK (view_navigation_action),
345 view);
347 priv->next_action = g_simple_action_new ("yelp-view-go-next", NULL);
348 g_simple_action_set_enabled (priv->next_action, FALSE);
349 g_signal_connect (priv->next_action,
350 "activate",
351 G_CALLBACK (view_navigation_action),
352 view);
355 static void
356 yelp_view_constructed (GObject *object)
358 YelpView *view = YELP_VIEW (object);
359 YelpViewPrivate *priv = GET_PRIV (view);
360 YelpSettings *settings = yelp_settings_get_default ();
362 G_OBJECT_CLASS (yelp_view_parent_class)->constructed (object);
364 g_signal_connect_swapped (webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (view)),
365 "changed",
366 G_CALLBACK (view_history_changed),
367 view);
369 priv->fonts_changed = g_signal_connect (settings,
370 "fonts-changed",
371 G_CALLBACK (settings_set_fonts),
372 view);
373 settings_set_fonts (settings, view);
376 static void
377 yelp_view_dispose (GObject *object)
379 YelpViewPrivate *priv = GET_PRIV (object);
381 view_clear_load (YELP_VIEW (object));
383 if (priv->fonts_changed > 0) {
384 g_signal_handler_disconnect (yelp_settings_get_default (),
385 priv->fonts_changed);
386 priv->fonts_changed = 0;
389 if (priv->print_action) {
390 g_object_unref (priv->print_action);
391 priv->print_action = NULL;
394 if (priv->back_action) {
395 g_object_unref (priv->back_action);
396 priv->back_action = NULL;
399 if (priv->forward_action) {
400 g_object_unref (priv->forward_action);
401 priv->forward_action = NULL;
404 if (priv->prev_action) {
405 g_object_unref (priv->prev_action);
406 priv->prev_action = NULL;
409 if (priv->next_action) {
410 g_object_unref (priv->next_action);
411 priv->next_action = NULL;
414 if (priv->document) {
415 g_object_unref (priv->document);
416 priv->document = NULL;
419 while (priv->link_actions) {
420 action_entry_free (priv->link_actions->data);
421 priv->link_actions = g_slist_delete_link (priv->link_actions, priv->link_actions);
424 G_OBJECT_CLASS (yelp_view_parent_class)->dispose (object);
427 static void
428 yelp_view_finalize (GObject *object)
430 YelpViewPrivate *priv = GET_PRIV (object);
432 g_free (priv->popup_link_uri);
433 g_free (priv->popup_link_text);
434 g_free (priv->popup_image_uri);
435 g_free (priv->popup_code_text);
436 g_free (priv->popup_code_title);
438 g_free (priv->page_id);
439 g_free (priv->root_title);
440 g_free (priv->page_title);
441 g_free (priv->page_desc);
442 g_free (priv->page_icon);
444 g_object_unref (priv->popup_actions);
446 G_OBJECT_CLASS (yelp_view_parent_class)->finalize (object);
449 static void
450 yelp_view_class_init (YelpViewClass *klass)
452 GObjectClass *object_class = G_OBJECT_CLASS (klass);
453 YelpSettings *settings = yelp_settings_get_default ();
455 nautilus_sendto = g_find_program_in_path ("nautilus-sendto");
457 g_signal_connect (settings,
458 "notify::show-text-cursor",
459 G_CALLBACK (settings_show_text_cursor),
460 NULL);
461 settings_show_text_cursor (settings);
463 yelp_view_register_extensions ();
464 yelp_view_register_custom_schemes ();
466 klass->external_uri = view_external_uri;
468 object_class->constructed = yelp_view_constructed;
469 object_class->dispose = yelp_view_dispose;
470 object_class->finalize = yelp_view_finalize;
471 object_class->get_property = yelp_view_get_property;
472 object_class->set_property = yelp_view_set_property;
474 signals[NEW_VIEW_REQUESTED] =
475 g_signal_new ("new-view-requested",
476 G_TYPE_FROM_CLASS (klass),
477 G_SIGNAL_RUN_LAST,
478 0, NULL, NULL,
479 g_cclosure_marshal_VOID__OBJECT,
480 G_TYPE_NONE, 1, YELP_TYPE_URI);
482 signals[EXTERNAL_URI] =
483 g_signal_new ("external-uri",
484 G_TYPE_FROM_CLASS (klass),
485 G_SIGNAL_RUN_LAST,
486 G_STRUCT_OFFSET (YelpViewClass, external_uri),
487 g_signal_accumulator_true_handled, NULL,
488 yelp_marshal_BOOLEAN__OBJECT,
489 G_TYPE_BOOLEAN, 1, YELP_TYPE_URI);
491 signals[LOADED] =
492 g_signal_new ("loaded",
493 G_TYPE_FROM_CLASS (klass),
494 G_SIGNAL_RUN_LAST,
495 0, NULL, NULL,
496 g_cclosure_marshal_VOID__VOID,
497 G_TYPE_NONE, 0);
499 g_type_class_add_private (klass, sizeof (YelpViewPrivate));
501 g_object_class_install_property (object_class,
502 PROP_URI,
503 g_param_spec_object ("yelp-uri",
504 "Yelp URI",
505 "A YelpUri with the current location",
506 YELP_TYPE_URI,
507 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
508 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
510 g_object_class_install_property (object_class,
511 PROP_STATE,
512 g_param_spec_enum ("state",
513 "Loading State",
514 "The loading state of the view",
515 YELP_TYPE_VIEW_STATE,
516 YELP_VIEW_STATE_BLANK,
517 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
518 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
520 g_object_class_install_property (object_class,
521 PROP_PAGE_ID,
522 g_param_spec_string ("page-id",
523 "Page ID",
524 "The ID of the root page of the page being viewed",
525 NULL,
526 G_PARAM_READABLE |
527 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
529 g_object_class_install_property (object_class,
530 PROP_ROOT_TITLE,
531 g_param_spec_string ("root-title",
532 "Root Title",
533 "The title of the root page of the page being viewed",
534 NULL,
535 G_PARAM_READABLE |
536 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
538 g_object_class_install_property (object_class,
539 PROP_PAGE_TITLE,
540 g_param_spec_string ("page-title",
541 "Page Title",
542 "The title of the page being viewed",
543 NULL,
544 G_PARAM_READABLE |
545 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
547 g_object_class_install_property (object_class,
548 PROP_PAGE_DESC,
549 g_param_spec_string ("page-desc",
550 "Page Description",
551 "The description of the page being viewed",
552 NULL,
553 G_PARAM_READABLE |
554 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
556 g_object_class_install_property (object_class,
557 PROP_PAGE_ICON,
558 g_param_spec_string ("page-icon",
559 "Page Icon",
560 "The icon of the page being viewed",
561 NULL,
562 G_PARAM_READABLE |
563 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
566 static void
567 yelp_view_get_property (GObject *object,
568 guint prop_id,
569 GValue *value,
570 GParamSpec *pspec)
572 YelpViewPrivate *priv = GET_PRIV (object);
574 switch (prop_id)
576 case PROP_URI:
577 g_value_set_object (value, priv->uri);
578 break;
579 case PROP_PAGE_ID:
580 g_value_set_string (value, priv->page_id);
581 break;
582 case PROP_ROOT_TITLE:
583 g_value_set_string (value, priv->root_title);
584 break;
585 case PROP_PAGE_TITLE:
586 g_value_set_string (value, priv->page_title);
587 break;
588 case PROP_PAGE_DESC:
589 g_value_set_string (value, priv->page_desc);
590 break;
591 case PROP_PAGE_ICON:
592 if (priv->page_icon)
593 g_value_set_string (value, priv->page_icon);
594 else
595 g_value_set_string (value, "yelp-page-symbolic");
596 break;
597 case PROP_STATE:
598 g_value_set_enum (value, priv->state);
599 break;
600 default:
601 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
602 break;
606 static void
607 yelp_view_set_property (GObject *object,
608 guint prop_id,
609 const GValue *value,
610 GParamSpec *pspec)
612 YelpUri *uri;
613 YelpViewPrivate *priv = GET_PRIV (object);
615 switch (prop_id)
617 case PROP_URI:
618 uri = g_value_get_object (value);
619 yelp_view_load_uri (YELP_VIEW (object), uri);
620 g_object_unref (uri);
621 break;
622 case PROP_STATE:
623 priv->prevstate = priv->state;
624 priv->state = g_value_get_enum (value);
625 break;
626 default:
627 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
628 break;
632 /******************************************************************************/
634 GtkWidget *
635 yelp_view_new (void)
637 return GTK_WIDGET (g_object_new (YELP_TYPE_VIEW,
638 "settings", yelp_view_get_global_settings (), NULL));
641 void
642 yelp_view_load (YelpView *view,
643 const gchar *uri)
645 YelpUri *yuri = yelp_uri_new (uri);
646 yelp_view_load_uri (view, yuri);
647 g_object_unref (yuri);
650 void
651 yelp_view_load_uri (YelpView *view,
652 YelpUri *uri)
654 YelpViewPrivate *priv = GET_PRIV (view);
656 g_object_set (view, "state", YELP_VIEW_STATE_LOADING, NULL);
658 g_simple_action_set_enabled (priv->prev_action, FALSE);
659 g_simple_action_set_enabled (priv->next_action, FALSE);
661 priv->load_page_after_resolved = TRUE;
662 yelp_view_resolve_uri (view, uri);
665 void
666 yelp_view_load_document (YelpView *view,
667 YelpUri *uri,
668 YelpDocument *document)
670 GParamSpec *spec;
671 YelpViewPrivate *priv = GET_PRIV (view);
673 g_return_if_fail (yelp_uri_is_resolved (uri));
675 g_object_set (view, "state", YELP_VIEW_STATE_LOADING, NULL);
677 g_object_ref (uri);
678 view_clear_load (view);
679 priv->uri = uri;
680 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
681 "yelp-uri");
682 g_signal_emit_by_name (view, "notify::yelp-uri", spec);
683 g_object_ref (document);
684 if (priv->document)
685 g_object_unref (document);
686 priv->document = document;
688 view_load_page (view);
691 YelpDocument *
692 yelp_view_get_document (YelpView *view)
694 YelpViewPrivate *priv = GET_PRIV (view);
695 return priv->document;
698 void
699 yelp_view_register_actions (YelpView *view,
700 GActionMap *map)
702 YelpViewPrivate *priv = GET_PRIV (view);
703 g_action_map_add_action (map, G_ACTION (priv->print_action));
704 g_action_map_add_action (map, G_ACTION (priv->back_action));
705 g_action_map_add_action (map, G_ACTION (priv->forward_action));
706 g_action_map_add_action (map, G_ACTION (priv->prev_action));
707 g_action_map_add_action (map, G_ACTION (priv->next_action));
710 /******************************************************************************/
712 static void
713 yelp_view_resolve_uri (YelpView *view,
714 YelpUri *uri)
716 YelpViewPrivate *priv = GET_PRIV (view);
718 if (yelp_uri_is_resolved (uri)) {
719 uri_resolved (uri, view);
720 return;
723 if (priv->resolve_uri != NULL) {
724 if (priv->uri_resolved != 0) {
725 g_signal_handler_disconnect (priv->resolve_uri, priv->uri_resolved);
726 priv->uri_resolved = 0;
728 g_object_unref (priv->resolve_uri);
730 priv->resolve_uri = g_object_ref (uri);
731 priv->uri_resolved = g_signal_connect (uri, "resolved",
732 G_CALLBACK (uri_resolved),
733 view);
734 yelp_uri_resolve (uri);
737 static void
738 document_callback (YelpDocument *document,
739 YelpDocumentSignal signal,
740 RequestAsyncData *data,
741 GError *error)
743 const gchar *contents;
744 gchar *mime_type;
745 GInputStream *stream;
746 int content_length;
748 if (signal == YELP_DOCUMENT_SIGNAL_INFO)
749 return;
751 if (signal == YELP_DOCUMENT_SIGNAL_ERROR) {
752 webkit_uri_scheme_request_finish_error (data->request, error);
753 return;
756 mime_type = yelp_document_get_mime_type (document, data->page_id);
758 contents = yelp_document_read_contents (document, data->page_id);
760 content_length = strlen (contents);
762 stream = g_memory_input_stream_new_from_data (g_strdup (contents), content_length, g_free);
763 yelp_document_finish_read (document, contents);
765 webkit_uri_scheme_request_finish (data->request,
766 stream,
767 content_length,
768 mime_type);
769 g_free (mime_type);
770 g_object_unref (stream);
773 static void
774 help_cb_uri_resolved (YelpUri *uri,
775 WebKitURISchemeRequest *request)
777 YelpDocument *document;
779 if ((document = yelp_document_get_for_uri (uri))) {
780 RequestAsyncData *data;
781 gchar * page_id;
783 page_id = yelp_uri_get_page_id (uri);
784 data = request_async_data_new (request, page_id);
785 g_free (page_id);
787 yelp_document_request_page (document,
788 data->page_id,
789 NULL,
790 (YelpDocumentCallback) document_callback,
791 data,
792 (GDestroyNotify) request_async_data_free);
793 g_object_unref (document);
795 } else {
796 YelpUriDocumentType doctype;
797 GError *error;
798 gchar *struri;
800 doctype = yelp_uri_get_document_type (uri);
801 if (doctype == YELP_URI_DOCUMENT_TYPE_NOT_FOUND) {
802 struri = yelp_uri_get_canonical_uri (uri);
803 if (struri) {
804 error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
805 _("The URI ā€˜%sā€™ does not point to a valid page."),
806 struri);
807 g_free (struri);
809 else {
810 error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
811 _("The URI does not point to a valid page."));
813 } else if (doctype == YELP_URI_DOCUMENT_TYPE_ERROR) {
814 struri = yelp_uri_get_canonical_uri (uri);
815 error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
816 _("The URI ā€˜%sā€™ could not be parsed."),
817 struri);
818 g_free (struri);
819 } else {
820 error = g_error_new (YELP_ERROR, YELP_ERROR_UNKNOWN,
821 _("Unknown Error."));
824 webkit_uri_scheme_request_finish_error (request, error);
825 g_error_free (error);
829 static void
830 help_uri_scheme_request_cb (WebKitURISchemeRequest *request,
831 gpointer user_data)
833 YelpUri *uri;
834 gchar *uri_str;
836 uri_str = build_yelp_uri (webkit_uri_scheme_request_get_uri (request));
838 uri = yelp_uri_new (uri_str);
839 g_free (uri_str);
841 g_signal_connect (uri, "resolved", G_CALLBACK (help_cb_uri_resolved), request);
842 yelp_uri_resolve (uri);
844 g_object_unref (uri);
847 static const gchar *help_schemes[] = { "help", "ghelp", "gnome-help", "help-list", "info", "man", NULL };
849 static void
850 yelp_view_register_custom_schemes (void)
852 WebKitWebContext *context = webkit_web_context_get_default ();
853 WebKitSecurityManager *sec_manager = webkit_web_context_get_security_manager (context);
854 gint i;
855 gchar *network_scheme;
857 for (i = 0; help_schemes[i] != NULL; i++) {
858 network_scheme = build_network_scheme (help_schemes[i]);
860 webkit_web_context_register_uri_scheme (context, network_scheme,
861 (WebKitURISchemeRequestCallback) help_uri_scheme_request_cb,
862 NULL, NULL);
864 webkit_security_manager_register_uri_scheme_as_local (sec_manager, network_scheme);
866 g_free (network_scheme);
870 /******************************************************************************/
872 void
873 yelp_view_add_link_action (YelpView *view,
874 GtkAction *action,
875 YelpViewActionValidFunc func,
876 gpointer data)
878 YelpActionEntry *entry;
879 YelpViewPrivate *priv = GET_PRIV (view);
881 entry = g_new0 (YelpActionEntry, 1);
882 entry->action = g_object_ref (action);
883 entry->func = func;
884 entry->data = data;
886 priv->link_actions = g_slist_append (priv->link_actions, entry);
889 YelpUri *
890 yelp_view_get_active_link_uri (YelpView *view)
892 YelpViewPrivate *priv = GET_PRIV (view);
893 YelpUri *uri;
895 uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
897 return uri;
900 gchar *
901 yelp_view_get_active_link_text (YelpView *view)
903 YelpViewPrivate *priv = GET_PRIV (view);
904 return g_strdup (priv->popup_link_text);
907 /******************************************************************************/
909 static void
910 yelp_view_register_extensions (void)
912 WebKitWebContext *context = webkit_web_context_get_default ();
914 webkit_web_context_set_web_extensions_directory (context, YELP_WEB_EXTENSIONS_DIR);
917 /******************************************************************************/
919 static gboolean
920 view_external_uri (YelpView *view,
921 YelpUri *uri)
923 gchar *struri = yelp_uri_get_canonical_uri (uri);
924 gchar *uri_scheme;
925 GAppInfo *app_info = NULL;
927 uri_scheme = g_uri_parse_scheme (struri);
928 if (uri_scheme && *uri_scheme)
929 app_info = g_app_info_get_default_for_uri_scheme (uri_scheme);
930 g_free (uri_scheme);
932 if (app_info)
934 if (!strstr (g_app_info_get_executable (app_info), "yelp"))
936 GList l;
938 l.data = struri;
939 l.next = l.prev = NULL;
940 g_app_info_launch_uris (app_info, &l, NULL, NULL);
943 g_object_unref (app_info);
945 g_free (struri);
946 return TRUE;
949 typedef struct _YelpInstallInfo YelpInstallInfo;
950 struct _YelpInstallInfo {
951 YelpView *view;
952 gchar *uri;
955 static void
956 yelp_install_info_free (YelpInstallInfo *info)
958 g_object_unref (info->view);
959 if (info->uri)
960 g_free (info->uri);
961 g_free (info);
964 static void
965 view_install_installed (GDBusConnection *connection,
966 GAsyncResult *res,
967 YelpInstallInfo *info)
969 GError *error = NULL;
970 g_dbus_connection_call_finish (connection, res, &error);
971 if (error) {
972 const gchar *err = NULL;
973 if (error->domain == G_DBUS_ERROR) {
974 if (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
975 err = _("You do not have PackageKit. Package install links require PackageKit.");
976 else
977 err = error->message;
979 if (err != NULL) {
980 GtkWidget *dialog = gtk_message_dialog_new (NULL, 0,
981 GTK_MESSAGE_ERROR,
982 GTK_BUTTONS_CLOSE,
983 "%s", err);
984 gtk_dialog_run ((GtkDialog *) dialog);
985 gtk_widget_destroy (dialog);
987 g_error_free (error);
989 else if (info->uri) {
990 gchar *struri, *docuri;
991 YelpViewPrivate *priv = GET_PRIV (info->view);
992 docuri = yelp_uri_get_document_uri (priv->uri);
993 if (g_str_equal (docuri, info->uri)) {
994 struri = yelp_uri_get_canonical_uri (priv->uri);
995 yelp_view_load (info->view, struri);
996 g_free (struri);
998 g_free (docuri);
1001 yelp_install_info_free (info);
1004 static void
1005 view_install_uri (YelpView *view,
1006 const gchar *uri)
1008 GDBusConnection *connection;
1009 GError *error = NULL;
1010 gboolean help = FALSE, ghelp = FALSE;
1011 GVariantBuilder *strv;
1012 YelpInstallInfo *info;
1013 guint32 xid = 0;
1014 YelpViewPrivate *priv = GET_PRIV (view);
1015 GtkWidget *gtkwin;
1016 GdkWindow *gdkwin;
1017 /* do not free */
1018 const gchar *pkg = NULL, *confirm_search;
1020 if (g_str_has_prefix (uri, "install-help:")) {
1021 help = TRUE;
1022 pkg = (gchar *) uri + 13;
1024 else if (g_str_has_prefix (uri, "install-ghelp:")) {
1025 ghelp = TRUE;
1026 pkg = (gchar *) uri + 14;
1028 else if (g_str_has_prefix (uri, "install:")) {
1029 pkg = (gchar *) uri + 8;
1032 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1033 if (connection == NULL) {
1034 g_warning ("Unable to connect to dbus: %s", error->message);
1035 g_error_free (error);
1036 return;
1039 info = g_new0 (YelpInstallInfo, 1);
1040 info->view = g_object_ref (view);
1042 gtkwin = gtk_widget_get_toplevel (GTK_WIDGET (view));
1043 if (gtkwin != NULL && gtk_widget_is_toplevel (gtkwin)) {
1044 gdkwin = gtk_widget_get_window (gtkwin);
1045 #ifdef GDK_WINDOWING_X11
1046 if (gdkwin != NULL && GDK_IS_X11_WINDOW (gdkwin))
1047 xid = gdk_x11_window_get_xid (gdkwin);
1048 #endif
1051 if (priv->state == YELP_VIEW_STATE_ERROR)
1052 confirm_search = "hide-confirm-search";
1053 else
1054 confirm_search = "";
1056 if (help || ghelp) {
1057 const gchar * const *datadirs = g_get_system_data_dirs ();
1058 gint datadirs_i;
1059 gchar *docbook, *fname;
1060 docbook = g_strconcat (pkg, ".xml", NULL);
1061 strv = g_variant_builder_new (G_VARIANT_TYPE ("as"));
1062 for (datadirs_i = 0; datadirs[datadirs_i] != NULL; datadirs_i++) {
1063 if (ghelp) {
1064 fname = g_build_filename (datadirs[datadirs_i], "gnome", "help",
1065 pkg, "C", "index.page", NULL);
1066 g_variant_builder_add (strv, "s", fname);
1067 g_free (fname);
1068 fname = g_build_filename (datadirs[datadirs_i], "gnome", "help",
1069 pkg, "C", docbook, NULL);
1070 g_variant_builder_add (strv, "s", fname);
1071 g_free (fname);
1073 else {
1074 fname = g_build_filename (datadirs[datadirs_i], "help", "C",
1075 pkg, "index.page", NULL);
1076 g_variant_builder_add (strv, "s", fname);
1077 g_free (fname);
1078 fname = g_build_filename (datadirs[datadirs_i], "help", "C",
1079 pkg, "index.docbook", NULL);
1080 g_variant_builder_add (strv, "s", fname);
1081 g_free (fname);
1084 g_free (docbook);
1085 info->uri = g_strconcat (ghelp ? "ghelp:" : "help:", pkg, NULL);
1086 g_dbus_connection_call (connection,
1087 "org.freedesktop.PackageKit",
1088 "/org/freedesktop/PackageKit",
1089 "org.freedesktop.PackageKit.Modify",
1090 "InstallProvideFiles",
1091 g_variant_new ("(uass)", xid, strv, confirm_search),
1092 NULL,
1093 G_DBUS_CALL_FLAGS_NONE,
1094 G_MAXINT, NULL,
1095 (GAsyncReadyCallback) view_install_installed,
1096 info);
1097 g_variant_builder_unref (strv);
1099 else {
1100 gchar **pkgs;
1101 gint i;
1102 strv = g_variant_builder_new (G_VARIANT_TYPE ("as"));
1103 pkgs = g_strsplit (pkg, ",", 0);
1104 for (i = 0; pkgs[i]; i++)
1105 g_variant_builder_add (strv, "s", pkgs[i]);
1106 g_strfreev (pkgs);
1107 g_dbus_connection_call (connection,
1108 "org.freedesktop.PackageKit",
1109 "/org/freedesktop/PackageKit",
1110 "org.freedesktop.PackageKit.Modify",
1111 "InstallPackageNames",
1112 g_variant_new ("(uass)", xid, strv, confirm_search),
1113 NULL,
1114 G_DBUS_CALL_FLAGS_NONE,
1115 G_MAXINT, NULL,
1116 (GAsyncReadyCallback) view_install_installed,
1117 info);
1118 g_variant_builder_unref (strv);
1121 g_object_unref (connection);
1124 static void
1125 popup_open_link (GtkAction *action,
1126 YelpView *view)
1128 YelpViewPrivate *priv = GET_PRIV (view);
1129 YelpUri *uri;
1131 uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
1133 yelp_view_load_uri (view, uri);
1134 g_object_unref (uri);
1136 g_free (priv->popup_link_uri);
1137 priv->popup_link_uri = NULL;
1139 g_free (priv->popup_link_text);
1140 priv->popup_link_text = NULL;
1143 static void
1144 popup_open_link_new (GtkAction *action,
1145 YelpView *view)
1147 YelpViewPrivate *priv = GET_PRIV (view);
1148 YelpUri *uri;
1150 uri = yelp_uri_new_relative (priv->uri, priv->popup_link_uri);
1152 g_free (priv->popup_link_uri);
1153 priv->popup_link_uri = NULL;
1155 g_free (priv->popup_link_text);
1156 priv->popup_link_text = NULL;
1158 g_signal_emit (view, signals[NEW_VIEW_REQUESTED], 0, uri);
1159 g_object_unref (uri);
1162 static void
1163 popup_copy_link (GtkAction *action,
1164 YelpView *view)
1166 YelpViewPrivate *priv = GET_PRIV (view);
1167 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (view), GDK_SELECTION_CLIPBOARD),
1168 priv->popup_link_uri,
1169 -1);
1172 typedef struct _YelpSaveData YelpSaveData;
1173 struct _YelpSaveData {
1174 GFile *orig;
1175 GFile *dest;
1176 YelpView *view;
1177 GtkWindow *window;
1180 static void
1181 file_copied (GFile *file,
1182 GAsyncResult *res,
1183 YelpSaveData *data)
1185 GError *error = NULL;
1186 if (!g_file_copy_finish (file, res, &error)) {
1187 GtkWidget *dialog = gtk_message_dialog_new (gtk_widget_get_visible (GTK_WIDGET (data->window)) ? data->window : NULL,
1188 GTK_DIALOG_DESTROY_WITH_PARENT,
1189 GTK_MESSAGE_ERROR,
1190 GTK_BUTTONS_OK,
1191 "%s", error->message);
1192 gtk_dialog_run (GTK_DIALOG (dialog));
1193 gtk_widget_destroy (dialog);
1195 g_object_unref (data->orig);
1196 g_object_unref (data->dest);
1197 g_object_unref (data->view);
1198 g_object_unref (data->window);
1201 static void
1202 popup_save_image (GtkAction *action,
1203 YelpView *view)
1205 YelpSaveData *data;
1206 GtkWidget *dialog, *window;
1207 gchar *basename;
1208 gint res;
1209 YelpViewPrivate *priv = GET_PRIV (view);
1211 for (window = gtk_widget_get_parent (GTK_WIDGET (view));
1212 window && !GTK_IS_WINDOW (window);
1213 window = gtk_widget_get_parent (window));
1215 data = g_new0 (YelpSaveData, 1);
1216 data->orig = g_file_new_for_uri (priv->popup_image_uri);
1217 data->view = g_object_ref (view);
1218 data->window = g_object_ref (GTK_WINDOW (window));
1219 g_free (priv->popup_image_uri);
1220 priv->popup_image_uri = NULL;
1222 dialog = gtk_file_chooser_dialog_new (_("Save Image"),
1223 GTK_WINDOW (window),
1224 GTK_FILE_CHOOSER_ACTION_SAVE,
1225 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1226 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
1227 NULL);
1228 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
1229 basename = g_file_get_basename (data->orig);
1230 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), basename);
1231 g_free (basename);
1232 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1233 g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP));
1235 res = gtk_dialog_run (GTK_DIALOG (dialog));
1237 if (res == GTK_RESPONSE_OK) {
1238 data->dest = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
1239 g_file_copy_async (data->orig, data->dest,
1240 G_FILE_COPY_OVERWRITE,
1241 G_PRIORITY_DEFAULT,
1242 NULL, NULL, NULL,
1243 (GAsyncReadyCallback) file_copied,
1244 data);
1246 else {
1247 g_object_unref (data->orig);
1248 g_object_unref (data->view);
1249 g_object_unref (data->window);
1250 g_free (data);
1253 gtk_widget_destroy (dialog);
1256 static void
1257 popup_send_image (GtkAction *action,
1258 YelpView *view)
1260 gchar *command;
1261 GAppInfo *app;
1262 GAppLaunchContext *context;
1263 GError *error = NULL;
1264 YelpViewPrivate *priv = GET_PRIV (view);
1266 command = g_strdup_printf ("%s %s", nautilus_sendto, priv->popup_image_uri);
1267 context = (GAppLaunchContext *) gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (view)));
1269 app = g_app_info_create_from_commandline (command, NULL, 0, &error);
1270 if (app) {
1271 g_app_info_launch (app, NULL, context, &error);
1272 g_object_unref (app);
1275 if (error) {
1276 g_debug ("Could not launch nautilus-sendto: %s", error->message);
1277 g_error_free (error);
1280 g_object_unref (context);
1281 g_free (command);
1282 g_free (priv->popup_image_uri);
1283 priv->popup_image_uri = NULL;
1286 static void
1287 popup_copy_code (GtkAction *action,
1288 YelpView *view)
1290 YelpViewPrivate *priv = GET_PRIV (view);
1291 GtkClipboard *clipboard;
1293 if (!priv->popup_code_text)
1294 return;
1296 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1297 gtk_clipboard_set_text (clipboard, priv->popup_code_text, -1);
1300 static void
1301 popup_save_code (GtkAction *action,
1302 YelpView *view)
1304 YelpViewPrivate *priv = GET_PRIV (view);
1305 GtkWidget *dialog, *window;
1306 gint res;
1308 if (!priv->popup_code_text)
1309 return;
1311 if (!g_str_has_suffix (priv->popup_code_text, "\n")) {
1312 gchar *tmp = g_strconcat (priv->popup_code_text, "\n", NULL);
1313 g_free (priv->popup_code_text);
1314 priv->popup_code_text = tmp;
1317 for (window = gtk_widget_get_parent (GTK_WIDGET (view));
1318 window && !GTK_IS_WINDOW (window);
1319 window = gtk_widget_get_parent (window));
1321 dialog = gtk_file_chooser_dialog_new (_("Save Code"),
1322 GTK_WINDOW (window),
1323 GTK_FILE_CHOOSER_ACTION_SAVE,
1324 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1325 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
1326 NULL);
1327 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
1329 if (priv->popup_code_title)
1330 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), priv->popup_code_title);
1332 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
1333 g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
1335 res = gtk_dialog_run (GTK_DIALOG (dialog));
1337 if (res == GTK_RESPONSE_OK) {
1338 GError *error = NULL;
1339 GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
1340 GFileOutputStream *stream = g_file_replace (file, NULL, FALSE,
1341 G_FILE_CREATE_NONE,
1342 NULL,
1343 &error);
1344 if (stream == NULL) {
1345 GtkWidget *dlg = gtk_message_dialog_new (gtk_widget_get_visible (window) ? GTK_WINDOW (window) : NULL,
1346 GTK_DIALOG_DESTROY_WITH_PARENT,
1347 GTK_MESSAGE_ERROR,
1348 GTK_BUTTONS_OK,
1349 "%s", error->message);
1350 gtk_dialog_run (GTK_DIALOG (dlg));
1351 gtk_widget_destroy (dlg);
1352 g_error_free (error);
1354 else {
1355 /* FIXME: we should do this async */
1356 GDataOutputStream *datastream = g_data_output_stream_new (G_OUTPUT_STREAM (stream));
1357 if (!g_data_output_stream_put_string (datastream, priv->popup_code_text, NULL, &error)) {
1358 GtkWidget *dlg = gtk_message_dialog_new (gtk_widget_get_visible (window) ? GTK_WINDOW (window) : NULL,
1359 GTK_DIALOG_DESTROY_WITH_PARENT,
1360 GTK_MESSAGE_ERROR,
1361 GTK_BUTTONS_OK,
1362 "%s", error->message);
1363 gtk_dialog_run (GTK_DIALOG (dlg));
1364 gtk_widget_destroy (dlg);
1365 g_error_free (error);
1367 g_object_unref (datastream);
1369 g_object_unref (file);
1372 gtk_widget_destroy (dialog);
1375 static void
1376 popup_copy_clipboard (GtkAction *action,
1377 YelpView *view)
1379 webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (view), WEBKIT_EDITING_COMMAND_COPY);
1382 static gboolean
1383 view_populate_context_menu (YelpView *view,
1384 WebKitContextMenu *context_menu,
1385 GdkEvent *event,
1386 WebKitHitTestResult *hit_test_result,
1387 gpointer user_data)
1389 YelpViewPrivate *priv = GET_PRIV (view);
1390 WebKitContextMenuItem *item;
1391 GtkAction *action;
1392 GVariant *dom_info_variant;
1393 GVariantDict dom_info_dict;
1395 webkit_context_menu_remove_all (context_menu);
1397 /* We extract the info about the dom tree that we build in the web-extension.*/
1398 dom_info_variant = webkit_context_menu_get_user_data (context_menu);
1399 if (dom_info_variant)
1400 g_variant_dict_init (&dom_info_dict, dom_info_variant);
1402 if (webkit_hit_test_result_context_is_link (hit_test_result)) {
1403 const gchar *uri = webkit_hit_test_result_get_link_uri (hit_test_result);
1404 g_free (priv->popup_link_uri);
1406 priv->popup_link_uri = build_yelp_uri (uri);
1408 g_clear_pointer (&priv->popup_link_text, g_free);
1409 if (dom_info_variant)
1410 g_variant_dict_lookup (&dom_info_dict, "link-title", "s",
1411 &(priv->popup_link_text));
1413 if (!priv->popup_link_text)
1414 priv->popup_link_text = g_strdup (uri);
1416 if (g_str_has_prefix (priv->popup_link_uri, "mailto:")) {
1417 gchar *label = g_strdup_printf (_("Send email to %s"),
1418 priv->popup_link_uri + 7);
1419 action = gtk_action_group_get_action (priv->popup_actions,
1420 "SendEmail");
1421 gtk_action_set_label (action, label);
1422 item = webkit_context_menu_item_new (action);
1423 webkit_context_menu_append (context_menu, item);
1424 g_free (label);
1426 else if (g_str_has_prefix (priv->popup_link_uri, "install:")) {
1427 action = gtk_action_group_get_action (priv->popup_actions,
1428 "InstallPackages");
1429 item = webkit_context_menu_item_new (action);
1430 webkit_context_menu_append (context_menu, item);
1432 else {
1433 GSList *l;
1435 action = gtk_action_group_get_action (priv->popup_actions,
1436 "OpenLink");
1437 item = webkit_context_menu_item_new (action);
1438 webkit_context_menu_append (context_menu, item);
1440 if (g_str_has_prefix (priv->popup_link_uri, "http://") ||
1441 g_str_has_prefix (priv->popup_link_uri, "https://")) {
1442 action = gtk_action_group_get_action (priv->popup_actions,
1443 "CopyLink");
1444 item = webkit_context_menu_item_new (action);
1445 webkit_context_menu_append (context_menu, item);
1447 else {
1448 action = gtk_action_group_get_action (priv->popup_actions,
1449 "OpenLinkNew");
1450 item = webkit_context_menu_item_new (action);
1451 webkit_context_menu_append (context_menu, item);
1454 for (l = priv->link_actions; l != NULL; l = l->next) {
1455 gboolean add;
1456 YelpActionEntry *entry = (YelpActionEntry *) l->data;
1457 if (entry->func == NULL)
1458 add = TRUE;
1459 else
1460 add = (* entry->func) (view, entry->action,
1461 priv->popup_link_uri,
1462 entry->data);
1463 if (add) {
1464 item = webkit_context_menu_item_new (entry->action);
1465 webkit_context_menu_append (context_menu, item);
1470 else {
1471 #if 0
1472 item = gtk_action_create_menu_item (gtk_action_group_get_action (priv->action_group,
1473 "YelpViewGoBack"));
1474 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1475 item = gtk_action_create_menu_item (gtk_action_group_get_action (priv->action_group,
1476 "YelpViewGoForward"));
1477 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1478 #endif
1481 if (webkit_hit_test_result_context_is_image (hit_test_result) ||
1482 webkit_hit_test_result_context_is_media (hit_test_result)) {
1483 /* This doesn't currently work for video with automatic controls,
1484 * because WebKit puts the hit test on the div with the controls.
1486 gboolean image = webkit_hit_test_result_context_is_image (hit_test_result);
1487 const gchar *uri = image ? webkit_hit_test_result_get_image_uri (hit_test_result) :
1488 webkit_hit_test_result_get_media_uri (hit_test_result);
1489 gchar *yelp_uri;
1490 g_free (priv->popup_image_uri);
1492 yelp_uri = build_yelp_uri (uri);
1494 if (g_str_has_prefix (yelp_uri, "help:") ||
1495 g_str_has_prefix (yelp_uri, "ghelp:") ||
1496 g_str_has_prefix (yelp_uri, "gnome-help:")) {
1497 gchar *image_uri = strstr (yelp_uri, "/");
1499 if (image_uri) {
1500 image_uri[0] = '\0';
1501 image_uri++;
1504 if (image_uri && image_uri[0] != '\0')
1505 priv->popup_image_uri = yelp_uri_locate_file_uri (priv->uri, image_uri);
1506 else
1507 priv->popup_image_uri = NULL;
1509 else {
1510 priv->popup_image_uri = yelp_uri;
1513 g_free (yelp_uri);
1515 item = webkit_context_menu_item_new_separator ();
1516 webkit_context_menu_append (context_menu, item);
1518 action = gtk_action_group_get_action (priv->popup_actions,
1519 "SaveMedia");
1521 gtk_action_set_label (action, image ? _("_Save Image Asā€¦") :
1522 _("_Save Video Asā€¦"));
1524 item = webkit_context_menu_item_new (action);
1525 webkit_context_menu_append (context_menu, item);
1527 if (nautilus_sendto) {
1528 action = gtk_action_group_get_action (priv->popup_actions,
1529 "SendMedia");
1530 gtk_action_set_label (action, image ? _("S_end Image Toā€¦") :
1531 _("S_end Video Toā€¦"));
1533 item = webkit_context_menu_item_new (action);
1534 webkit_context_menu_append (context_menu, item);
1538 if (webkit_hit_test_result_context_is_selection (hit_test_result)) {
1539 item = webkit_context_menu_item_new_separator ();
1540 webkit_context_menu_append (context_menu, item);
1542 action = gtk_action_group_get_action (priv->popup_actions,
1543 "CopyText");
1544 item = webkit_context_menu_item_new (action);
1545 webkit_context_menu_append (context_menu, item);
1548 g_clear_pointer (&priv->popup_code_title, g_free);
1549 if (dom_info_variant)
1550 g_variant_dict_lookup (&dom_info_dict, "code-title",
1551 "s", &(priv->popup_code_title));
1553 g_clear_pointer (&priv->popup_code_text, g_free);
1554 if (dom_info_variant)
1555 g_variant_dict_lookup (&dom_info_dict, "code-text",
1556 "s", &(priv->popup_code_text));
1558 if (priv->popup_code_text) {
1559 item = webkit_context_menu_item_new_separator ();
1560 webkit_context_menu_append (context_menu, item);
1562 action = gtk_action_group_get_action (priv->popup_actions,
1563 "CopyCode");
1564 item = webkit_context_menu_item_new (action);
1565 webkit_context_menu_append (context_menu, item);
1567 action = gtk_action_group_get_action (priv->popup_actions,
1568 "SaveCode");
1569 item = webkit_context_menu_item_new (action);
1570 webkit_context_menu_append (context_menu, item);
1573 return FALSE;
1576 static gboolean
1577 view_script_dialog (YelpView *view,
1578 WebKitScriptDialog *dialog,
1579 gpointer data)
1581 WebKitScriptDialogType type = webkit_script_dialog_get_dialog_type (dialog);
1583 if (type != WEBKIT_SCRIPT_DIALOG_ALERT)
1584 return FALSE;
1586 printf ("\n\n===ALERT===\n%s\n\n", webkit_script_dialog_get_message (dialog));
1587 return TRUE;
1590 static gboolean
1591 view_policy_decision_requested (YelpView *view,
1592 WebKitPolicyDecision *decision,
1593 WebKitPolicyDecisionType type,
1594 gpointer user_data)
1596 YelpViewPrivate *priv = GET_PRIV (view);
1597 WebKitNavigationAction *action;
1598 WebKitURIRequest *request;
1599 gchar *fixed_uri;
1600 YelpUri *uri;
1602 if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
1603 return FALSE;
1605 if (!priv->resolve_uri_on_policy_decision) {
1606 priv->resolve_uri_on_policy_decision = TRUE;
1607 return FALSE;
1610 action = webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION (decision));
1611 request = webkit_navigation_action_get_request (action);
1612 fixed_uri = build_yelp_uri (webkit_uri_request_get_uri (request));
1613 if (webkit_navigation_action_get_navigation_type (action) == WEBKIT_NAVIGATION_TYPE_BACK_FORWARD) {
1614 uri = yelp_uri_new (fixed_uri);
1615 priv->load_page_after_resolved = FALSE;
1616 yelp_view_resolve_uri (view, uri);
1617 g_object_unref (uri);
1618 g_free (fixed_uri);
1620 return FALSE;
1623 webkit_policy_decision_ignore (decision);
1625 uri = yelp_uri_new_relative (priv->uri, fixed_uri);
1626 yelp_view_load_uri ((YelpView *) view, uri);
1627 g_object_unref (uri);
1628 g_free (fixed_uri);
1630 return TRUE;
1633 static void
1634 view_load_status_changed (WebKitWebView *view,
1635 WebKitLoadEvent load_event,
1636 gpointer user_data)
1638 YelpViewPrivate *priv = GET_PRIV (view);
1640 if (priv->state == YELP_VIEW_STATE_ERROR)
1641 return;
1643 switch (load_event) {
1644 case WEBKIT_LOAD_COMMITTED: {
1645 gchar *real_id;
1646 GParamSpec *spec;
1648 real_id = yelp_document_get_page_id (priv->document, priv->page_id);
1649 if (priv->page_id && real_id && g_str_equal (real_id, priv->page_id)) {
1650 g_free (real_id);
1652 else {
1653 g_free (priv->page_id);
1654 priv->page_id = real_id;
1655 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1656 "page-id");
1657 g_signal_emit_by_name (view, "notify::page-id", spec);
1660 g_free (priv->root_title);
1661 g_free (priv->page_title);
1662 g_free (priv->page_desc);
1663 g_free (priv->page_icon);
1665 priv->root_title = yelp_document_get_root_title (priv->document, priv->page_id);
1666 priv->page_title = yelp_document_get_page_title (priv->document, priv->page_id);
1667 priv->page_desc = yelp_document_get_page_desc (priv->document, priv->page_id);
1668 priv->page_icon = yelp_document_get_page_icon (priv->document, priv->page_id);
1670 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1671 "root-title");
1672 g_signal_emit_by_name (view, "notify::root-title", spec);
1674 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1675 "page-title");
1676 g_signal_emit_by_name (view, "notify::page-title", spec);
1678 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1679 "page-desc");
1680 g_signal_emit_by_name (view, "notify::page-desc", spec);
1682 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1683 "page-icon");
1684 g_signal_emit_by_name (view, "notify::page-icon", spec);
1685 break;
1687 case WEBKIT_LOAD_FINISHED:
1688 g_object_set (view, "state", YELP_VIEW_STATE_LOADED, NULL);
1690 /* If the document didn't give us a page title, get it from WebKit.
1691 * We let the main loop run through so that WebKit gets the title
1692 * set so that we can send notify::page-title before loaded. It
1693 * simplifies things if YelpView consumers can assume the title
1694 * is set before loaded is triggered.
1696 if (priv->page_title == NULL) {
1697 GParamSpec *spec;
1698 priv->page_title = g_strdup (webkit_web_view_get_title (view));
1699 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
1700 "page-title");
1701 g_signal_emit_by_name (view, "notify::page-title", spec);
1704 g_signal_emit (view, signals[LOADED], 0);
1706 break;
1707 case WEBKIT_LOAD_STARTED:
1708 case WEBKIT_LOAD_REDIRECTED:
1709 default:
1710 break;
1714 static void
1715 view_load_failed (WebKitWebView *view,
1716 WebKitLoadEvent load_event,
1717 gchar *failing_uri,
1718 GError *error,
1719 gpointer user_data)
1721 view_show_error_page (YELP_VIEW (view), error);
1724 static void
1725 view_print_action (GAction *action, GVariant *parameter, YelpView *view)
1727 GtkWidget *window;
1728 WebKitPrintOperation *print_operation;
1729 GtkPrintSettings *settings;
1730 YelpViewPrivate *priv = GET_PRIV (view);
1732 window = gtk_widget_get_toplevel (GTK_WIDGET (view));
1734 print_operation = webkit_print_operation_new (WEBKIT_WEB_VIEW (view));
1736 settings = gtk_print_settings_new ();
1737 gtk_print_settings_set (settings,
1738 GTK_PRINT_SETTINGS_OUTPUT_BASENAME,
1739 priv->page_title);
1740 webkit_print_operation_set_print_settings (print_operation, settings);
1742 webkit_print_operation_run_dialog (print_operation, GTK_WINDOW (window));
1743 g_object_unref (print_operation);
1744 g_object_unref (settings);
1747 static void
1748 view_history_action (GAction *action,
1749 GVariant *parameter,
1750 YelpView *view)
1752 if (g_str_equal (g_action_get_name (action), "yelp-view-go-back"))
1753 webkit_web_view_go_back (WEBKIT_WEB_VIEW (view));
1754 else
1755 webkit_web_view_go_forward (WEBKIT_WEB_VIEW (view));
1758 static void
1759 view_history_changed (YelpView *view)
1761 YelpViewPrivate *priv = GET_PRIV (view);
1762 WebKitWebView *web_view = WEBKIT_WEB_VIEW (view);
1764 g_simple_action_set_enabled (priv->back_action, webkit_web_view_can_go_back (web_view));
1765 g_simple_action_set_enabled (priv->forward_action, webkit_web_view_can_go_forward (web_view));
1768 static void
1769 view_navigation_action (GAction *action,
1770 GVariant *parameter,
1771 YelpView *view)
1773 YelpViewPrivate *priv = GET_PRIV (view);
1774 gchar *page_id, *new_id, *xref;
1775 YelpUri *new_uri;
1777 page_id = yelp_uri_get_page_id (priv->uri);
1779 if (g_str_equal (g_action_get_name (action), "yelp-view-go-previous"))
1780 new_id = yelp_document_get_prev_id (priv->document, page_id);
1781 else
1782 new_id = yelp_document_get_next_id (priv->document, page_id);
1784 /* Just in case we screwed up somewhere */
1785 if (new_id == NULL) {
1786 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
1787 return;
1790 xref = g_strconcat ("xref:", new_id, NULL);
1791 new_uri = yelp_uri_new_relative (priv->uri, xref);
1792 yelp_view_load_uri (view, new_uri);
1794 g_free (xref);
1795 g_free (new_id);
1796 g_object_unref (new_uri);
1799 static void
1800 view_clear_load (YelpView *view)
1802 YelpViewPrivate *priv = GET_PRIV (view);
1804 if (priv->resolve_uri != NULL) {
1805 if (priv->uri_resolved != 0) {
1806 g_signal_handler_disconnect (priv->resolve_uri, priv->uri_resolved);
1807 priv->uri_resolved = 0;
1809 g_object_unref (priv->resolve_uri);
1811 priv->resolve_uri = NULL;
1813 if (priv->uri) {
1814 g_object_unref (priv->uri);
1815 priv->uri = NULL;
1818 if (priv->cancellable) {
1819 g_cancellable_cancel (priv->cancellable);
1820 priv->cancellable = NULL;
1824 static gchar*
1825 fix_docbook_uri (YelpUri *docbook_uri, YelpDocument* document)
1827 SoupURI *soup_uri;
1828 gchar *retval, *canonical;
1830 canonical = yelp_uri_get_canonical_uri (docbook_uri);
1831 soup_uri = soup_uri_new (canonical);
1832 g_free (canonical);
1834 /* We don't have actual page and frag IDs for DocBook. We just map IDs
1835 of block elements. The result is that we get xref:someid#someid.
1836 If someid is really the page ID, we just drop the frag reference.
1837 Otherwise, normal page views scroll past the link trail.
1839 if (soup_uri->fragment && YELP_IS_DOCBOOK_DOCUMENT (document)) {
1840 gchar *page_id = yelp_uri_get_page_id (docbook_uri);
1841 gchar *real_id = yelp_document_get_page_id (document, page_id);
1843 if (g_str_equal (real_id, soup_uri->fragment))
1844 soup_uri_set_fragment (soup_uri, NULL);
1846 g_free (real_id);
1847 g_free (page_id);
1850 retval = soup_uri_to_string (soup_uri, FALSE);
1851 soup_uri_free (soup_uri);
1853 return retval;
1856 static void
1857 view_load_page (YelpView *view)
1859 YelpViewPrivate *priv = GET_PRIV (view);
1860 gchar *uri_str, *tmp_uri;
1862 g_return_if_fail (priv->cancellable == NULL);
1864 if (priv->document == NULL) {
1865 GError *error;
1866 gchar *docuri;
1867 /* FIXME: and if priv->uri is NULL? */
1868 docuri = yelp_uri_get_document_uri (priv->uri);
1869 /* FIXME: CANT_READ isn't right */
1870 if (docuri) {
1871 error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
1872 _("Could not load a document for ā€˜%sā€™"),
1873 docuri);
1874 g_free (docuri);
1876 else {
1877 error = g_error_new (YELP_ERROR, YELP_ERROR_CANT_READ,
1878 _("Could not load a document"));
1880 view_show_error_page (view, error);
1881 g_error_free (error);
1882 return;
1885 uri_str = yelp_uri_get_canonical_uri (priv->uri);
1887 if (YELP_IS_DOCBOOK_DOCUMENT (priv->document)){
1888 tmp_uri = uri_str;
1889 uri_str = fix_docbook_uri (priv->uri, priv->document);
1890 g_free (tmp_uri);
1893 tmp_uri = uri_str;
1894 uri_str = build_network_uri (uri_str);
1895 g_free (tmp_uri);
1897 priv->resolve_uri_on_policy_decision = FALSE;
1898 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), uri_str);
1900 g_free (uri_str);
1903 #define FORMAT_ERRORPAGE \
1904 "<html><head>" \
1905 "<style type='text/css'>" \
1906 "body {" \
1907 " margin: 1em;" \
1908 " color: %s;" \
1909 " background-color: %s;" \
1910 " }\n" \
1911 "p { margin: 1em 0 0 0; }\n" \
1912 "div.note {" \
1913 " padding: 6px;" \
1914 " border-color: %s;" \
1915 " border-top: solid 1px;" \
1916 " border-bottom: solid 1px;" \
1917 " background-color: %s;" \
1918 " }\n" \
1919 "div.note div.inner {" \
1920 " margin: 0; padding: 0;" \
1921 " background-image: url(%s);" \
1922 " background-position: %s top;" \
1923 " background-repeat: no-repeat;" \
1924 " min-height: %ipx;" \
1925 " }\n" \
1926 "div.note div.contents {" \
1927 " margin-%s: %ipx;" \
1928 " }\n" \
1929 "div.note div.title {" \
1930 " margin-%s: %ipx;" \
1931 " margin-bottom: 0.2em;" \
1932 " font-weight: bold;" \
1933 " color: %s;" \
1934 " }\n" \
1935 "a { color: %s; text-decoration: none; }\n" \
1936 "</style>" \
1937 "</head><body>" \
1938 "<div class='note'><div class='inner'>" \
1939 "%s<div class='contents'>%s%s</div>" \
1940 "</div></div>" \
1941 "</body></html>"
1943 static void
1944 view_show_error_page (YelpView *view,
1945 GError *error)
1947 YelpViewPrivate *priv = GET_PRIV (view);
1948 YelpSettings *settings = yelp_settings_get_default ();
1949 gchar *page, *title = NULL, *title_m, *content_beg, *content_end;
1950 gchar *textcolor, *bgcolor, *noteborder, *notebg, *titlecolor, *noteicon, *linkcolor;
1951 gint iconsize;
1952 GParamSpec *spec;
1953 gboolean doc404 = FALSE;
1954 const gchar *left = (gtk_widget_get_direction ((GtkWidget *) view) == GTK_TEXT_DIR_RTL) ? "right" : "left";
1956 if (priv->uri && yelp_uri_get_document_type (priv->uri) == YELP_URI_DOCUMENT_TYPE_NOT_FOUND)
1957 doc404 = TRUE;
1958 if (error->domain == YELP_ERROR)
1959 switch (error->code) {
1960 case YELP_ERROR_NOT_FOUND:
1961 if (doc404)
1962 title = _("Document Not Found");
1963 else
1964 title = _("Page Not Found");
1965 break;
1966 case YELP_ERROR_CANT_READ:
1967 title = _("Cannot Read");
1968 break;
1969 default:
1970 break;
1972 if (title == NULL)
1973 title = _("Unknown Error");
1974 title_m = g_markup_printf_escaped ("<div class='title'>%s</div>", title);
1976 content_beg = g_markup_printf_escaped ("<p>%s</p>", error->message);
1977 content_end = NULL;
1978 if (doc404) {
1979 gchar *struri = yelp_uri_get_document_uri (priv->uri);
1980 /* do not free */
1981 const gchar *pkg = NULL, *scheme = NULL;
1982 if (g_str_has_prefix (struri, "help:")) {
1983 scheme = "help";
1984 pkg = struri + 5;
1986 else if (g_str_has_prefix (struri, "ghelp:")) {
1987 scheme = "ghelp";
1988 pkg = struri + 6;
1990 if (pkg != NULL)
1991 content_end = g_markup_printf_escaped ("<p><a href='install-%s:%s'>%s</a></p>",
1992 scheme, pkg,
1993 _("Search for packages containing this document."));
1994 g_free (struri);
1997 textcolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_TEXT);
1998 bgcolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_BASE);
1999 noteborder = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_RED_BORDER);
2000 notebg = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_YELLOW_BASE);
2001 titlecolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_TEXT_LIGHT);
2002 linkcolor = yelp_settings_get_color (settings, YELP_SETTINGS_COLOR_LINK);
2003 noteicon = yelp_settings_get_icon (settings, YELP_SETTINGS_ICON_WARNING);
2004 iconsize = yelp_settings_get_icon_size (settings) + 6;
2006 page = g_strdup_printf (FORMAT_ERRORPAGE,
2007 textcolor, bgcolor, noteborder, notebg, noteicon,
2008 left, iconsize, left, iconsize, left, iconsize,
2009 titlecolor, linkcolor, title_m, content_beg,
2010 (content_end != NULL) ? content_end : "");
2012 g_object_set (view, "state", YELP_VIEW_STATE_ERROR, NULL);
2014 if (doc404) {
2015 g_free (priv->root_title);
2016 priv->root_title = g_strdup (title);
2017 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2018 "root-title");
2019 g_signal_emit_by_name (view, "notify::root-title", spec);
2020 g_free (priv->page_id);
2021 priv->page_id = g_strdup ("index");
2022 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2023 "page-id");
2024 g_signal_emit_by_name (view, "notify::page-id", spec);
2027 g_free (priv->page_title);
2028 priv->page_title = g_strdup (title);
2029 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2030 "page-title");
2031 g_signal_emit_by_name (view, "notify::page-title", spec);
2033 g_free (priv->page_desc);
2034 priv->page_desc = NULL;
2035 if (priv->uri)
2036 priv->page_desc = yelp_uri_get_canonical_uri (priv->uri);
2037 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2038 "page-desc");
2039 g_signal_emit_by_name (view, "notify::page-desc", spec);
2041 g_free (priv->page_icon);
2042 priv->page_icon = g_strdup ("dialog-warning");
2043 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2044 "page-icon");
2045 g_signal_emit_by_name (view, "notify::page-icon", spec);
2047 g_signal_emit (view, signals[LOADED], 0);
2049 priv->resolve_uri_on_policy_decision = FALSE;
2050 webkit_web_view_load_html (WEBKIT_WEB_VIEW (view),
2051 page,
2052 "file:///error/");
2053 g_free (title_m);
2054 g_free (content_beg);
2055 if (content_end != NULL)
2056 g_free (content_end);
2059 static void
2060 settings_set_fonts (YelpSettings *settings,
2061 gpointer user_data)
2063 YelpView *view;
2064 gchar *family;
2065 gint size;
2067 view = (YelpView *) user_data;
2069 family = yelp_settings_get_font_family (settings,
2070 YELP_SETTINGS_FONT_VARIABLE);
2071 size = yelp_settings_get_font_size (settings,
2072 YELP_SETTINGS_FONT_VARIABLE);
2073 g_object_set (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)),
2074 "default-font-family", family,
2075 "sans-serif-font-family", family,
2076 "default-font-size", webkit_settings_font_size_to_pixels (size),
2077 NULL);
2078 g_free (family);
2080 family = yelp_settings_get_font_family (settings,
2081 YELP_SETTINGS_FONT_FIXED);
2082 size = yelp_settings_get_font_size (settings,
2083 YELP_SETTINGS_FONT_FIXED);
2084 g_object_set (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)),
2085 "monospace-font-family", family,
2086 "default-monospace-font-size", webkit_settings_font_size_to_pixels (size),
2087 NULL);
2088 g_free (family);
2091 static void
2092 settings_show_text_cursor (YelpSettings *settings)
2094 webkit_settings_set_enable_caret_browsing (yelp_view_get_global_settings (),
2095 yelp_settings_get_show_text_cursor (settings));
2098 /******************************************************************************/
2100 static void
2101 uri_resolved (YelpUri *uri,
2102 YelpView *view)
2104 YelpViewPrivate *priv = GET_PRIV (view);
2105 YelpUriDocumentType doctype;
2106 YelpDocument *document;
2107 GError *error = NULL;
2108 gchar *struri;
2109 GParamSpec *spec;
2111 doctype = yelp_uri_get_document_type (uri);
2113 if (doctype != YELP_URI_DOCUMENT_TYPE_EXTERNAL) {
2114 g_object_ref (uri);
2115 view_clear_load (view);
2116 priv->uri = uri;
2119 if (doctype == YELP_URI_DOCUMENT_TYPE_EXTERNAL) {
2120 g_object_set (view, "state", priv->prevstate, NULL);
2121 struri = yelp_uri_get_canonical_uri (uri);
2122 if (g_str_has_prefix (struri, "install:") ||
2123 g_str_has_prefix (struri, "install-ghelp:") ||
2124 g_str_has_prefix (struri, "install-help:")) {
2125 view_install_uri (view, struri);
2127 else {
2128 gboolean result;
2129 g_signal_emit (view, signals[EXTERNAL_URI], 0, uri, &result);
2131 g_free (struri);
2132 return;
2134 else if (doctype == YELP_URI_DOCUMENT_TYPE_NOT_FOUND) {
2135 struri = yelp_uri_get_canonical_uri (uri);
2136 if (struri != NULL) {
2137 error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
2138 _("The URI ā€˜%sā€™ does not point to a valid page."),
2139 struri);
2140 g_free (struri);
2142 else {
2143 error = g_error_new (YELP_ERROR, YELP_ERROR_NOT_FOUND,
2144 _("The URI does not point to a valid page."));
2147 else if (doctype == YELP_URI_DOCUMENT_TYPE_ERROR) {
2148 struri = yelp_uri_get_canonical_uri (uri);
2149 error = g_error_new (YELP_ERROR, YELP_ERROR_PROCESSING,
2150 _("The URI ā€˜%sā€™ could not be parsed."),
2151 struri);
2152 g_free (struri);
2155 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2156 "yelp-uri");
2157 g_signal_emit_by_name (view, "notify::yelp-uri", spec);
2159 g_free (priv->page_id);
2160 priv->page_id = NULL;
2161 if (priv->uri != NULL)
2162 priv->page_id = yelp_uri_get_page_id (priv->uri);
2163 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2164 "page-id");
2165 g_signal_emit_by_name (view, "notify::page-id", spec);
2167 g_free (priv->root_title);
2168 g_free (priv->page_title);
2169 g_free (priv->page_desc);
2170 g_free (priv->page_icon);
2171 priv->root_title = NULL;
2172 priv->page_title = NULL;
2173 priv->page_desc = NULL;
2174 priv->page_icon = NULL;
2176 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2177 "root-title");
2178 g_signal_emit_by_name (view, "notify::root-title", spec);
2180 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2181 "page-title");
2182 g_signal_emit_by_name (view, "notify::page-title", spec);
2184 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2185 "page-desc");
2186 g_signal_emit_by_name (view, "notify::page-desc", spec);
2188 spec = g_object_class_find_property ((GObjectClass *) YELP_VIEW_GET_CLASS (view),
2189 "page-icon");
2190 g_signal_emit_by_name (view, "notify::page-icon", spec);
2192 if (error == NULL) {
2193 document = yelp_document_get_for_uri (uri);
2194 if (priv->document)
2195 g_object_unref (priv->document);
2196 priv->document = document;
2198 if (priv->load_page_after_resolved)
2199 view_load_page (view);
2200 } else {
2201 if (priv->document != NULL) {
2202 g_object_unref (priv->document);
2203 priv->document = NULL;
2205 view_show_error_page (view, error);
2206 g_error_free (error);