1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Copyright (C) 2009 Shaun McCance <shaunm@gnome.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Shaun McCance <shaunm@gnome.org>
25 #include <glib/gi18n.h>
26 #include <glib-object.h>
30 #include <webkit/webkit.h>
32 #include "yelp-debug.h"
33 #include "yelp-docbook-document.h"
34 #include "yelp-error.h"
35 #include "yelp-marshal.h"
36 #include "yelp-settings.h"
37 #include "yelp-types.h"
38 #include "yelp-view.h"
40 #define BOGUS_URI "file:///bogus/"
41 #define BOGUS_URI_LEN 14
43 static void yelp_view_init (YelpView
*view
);
44 static void yelp_view_class_init (YelpViewClass
*klass
);
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
,
51 static void yelp_view_set_property (GObject
*object
,
56 static gboolean
view_external_uri (YelpView
*view
,
58 static void view_install_uri (YelpView
*view
,
60 static void view_scrolled (GtkAdjustment
*adjustment
,
62 static void view_set_hadjustment (YelpView
*view
,
65 static void view_set_vadjustment (YelpView
*view
,
68 static void popup_open_link (GtkMenuItem
*item
,
70 static void popup_open_link_new (GtkMenuItem
*item
,
72 static void popup_copy_link (GtkMenuItem
*item
,
74 static void popup_save_image (GtkMenuItem
*item
,
76 static void popup_send_image (GtkMenuItem
*item
,
78 static void popup_copy_code (GtkMenuItem
*item
,
80 static void popup_save_code (GtkMenuItem
*item
,
82 static void view_populate_popup (YelpView
*view
,
85 static void view_script_alert (YelpView
*view
,
86 WebKitWebFrame
*frame
,
89 static gboolean
view_navigation_requested (WebKitWebView
*view
,
90 WebKitWebFrame
*frame
,
91 WebKitNetworkRequest
*request
,
92 WebKitWebNavigationAction
*action
,
93 WebKitWebPolicyDecision
*decision
,
95 static void view_resource_request (WebKitWebView
*view
,
96 WebKitWebFrame
*frame
,
97 WebKitWebResource
*resource
,
98 WebKitNetworkRequest
*request
,
99 WebKitNetworkResponse
*response
,
101 static void view_document_loaded (WebKitWebView
*view
,
102 WebKitWebFrame
*frame
,
105 static void view_print (GtkAction
*action
,
107 static void view_history_action (GtkAction
*action
,
109 static void view_navigation_action (GtkAction
*action
,
112 static void view_clear_load (YelpView
*view
);
113 static void view_load_page (YelpView
*view
);
114 static void view_show_error_page (YelpView
*view
,
117 static void settings_set_fonts (YelpSettings
*settings
);
118 static void settings_show_text_cursor (YelpSettings
*settings
);
120 static void uri_resolved (YelpUri
*uri
,
122 static void document_callback (YelpDocument
*document
,
123 YelpDocumentSignal signal
,
127 static const GtkActionEntry entries
[] = {
128 {"YelpViewPrint", GTK_STOCK_PRINT
,
132 G_CALLBACK (view_print
) },
133 {"YelpViewGoBack", GTK_STOCK_GO_BACK
,
137 G_CALLBACK (view_history_action
) },
138 {"YelpViewGoForward", GTK_STOCK_GO_FORWARD
,
142 G_CALLBACK (view_history_action
) },
143 {"YelpViewGoPrevious", NULL
,
144 N_("_Previous Page"),
147 G_CALLBACK (view_navigation_action
) },
148 {"YelpViewGoNext", NULL
,
150 "<Control>Page_Down",
152 G_CALLBACK (view_navigation_action
) }
155 static gchar
*nautilus_sendto
= NULL
;
174 static gint signals
[LAST_SIGNAL
] = { 0 };
176 G_DEFINE_TYPE (YelpView
, yelp_view
, WEBKIT_TYPE_WEB_VIEW
);
177 #define GET_PRIV(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_VIEW, YelpViewPrivate))
179 static WebKitWebSettings
*websettings
;
181 typedef struct _YelpActionEntry YelpActionEntry
;
182 struct _YelpActionEntry
{
184 YelpViewActionValidFunc func
;
188 action_entry_free (YelpActionEntry
*entry
)
192 g_object_unref (entry
->action
);
196 typedef struct _YelpBackEntry YelpBackEntry
;
197 struct _YelpBackEntry
{
205 back_entry_free (YelpBackEntry
*back
)
209 g_object_unref (back
->uri
);
210 g_free (back
->title
);
215 typedef struct _YelpViewPrivate YelpViewPrivate
;
216 struct _YelpViewPrivate
{
218 YelpUri
*resolve_uri
;
221 YelpDocument
*document
;
222 GCancellable
*cancellable
;
223 GtkAdjustment
*vadjustment
;
224 GtkAdjustment
*hadjustment
;
230 gchar
*popup_link_uri
;
231 gchar
*popup_link_text
;
232 gchar
*popup_image_uri
;
233 WebKitDOMNode
*popup_code_node
;
234 WebKitDOMNode
*popup_code_title
;
235 gchar
*popup_code_text
;
238 YelpViewState prevstate
;
250 GtkActionGroup
*action_group
;
252 GSList
*link_actions
;
254 gint navigation_requested
;
257 #define TARGET_TYPE_URI_LIST "text/uri-list"
263 yelp_view_init (YelpView
*view
)
266 YelpViewPrivate
*priv
= GET_PRIV (view
);
268 g_object_set (view
, "settings", websettings
, NULL
);
270 priv
->cancellable
= NULL
;
272 priv
->prevstate
= priv
->state
= YELP_VIEW_STATE_BLANK
;
274 priv
->navigation_requested
=
275 g_signal_connect (view
, "navigation-policy-decision-requested",
276 G_CALLBACK (view_navigation_requested
), NULL
);
277 g_signal_connect (view
, "resource-request-starting",
278 G_CALLBACK (view_resource_request
), NULL
);
279 g_signal_connect (view
, "document-load-finished",
280 G_CALLBACK (view_document_loaded
), NULL
);
281 g_signal_connect (view
, "notify::hadjustment",
282 G_CALLBACK (view_set_hadjustment
), NULL
);
283 g_signal_connect (view
, "notify::vadjustment",
284 G_CALLBACK (view_set_vadjustment
), NULL
);
285 g_signal_connect (view
, "populate-popup",
286 G_CALLBACK (view_populate_popup
), NULL
);
287 g_signal_connect (view
, "script-alert",
288 G_CALLBACK (view_script_alert
), NULL
);
290 priv
->action_group
= gtk_action_group_new ("YelpView");
291 gtk_action_group_set_translation_domain (priv
->action_group
, GETTEXT_PACKAGE
);
292 gtk_action_group_add_actions (priv
->action_group
,
293 entries
, G_N_ELEMENTS (entries
),
295 action
= gtk_action_group_get_action (priv
->action_group
, "YelpViewGoBack");
296 gtk_action_set_sensitive (action
, FALSE
);
297 action
= gtk_action_group_get_action (priv
->action_group
, "YelpViewGoForward");
298 gtk_action_set_sensitive (action
, FALSE
);
302 yelp_view_dispose (GObject
*object
)
304 YelpViewPrivate
*priv
= GET_PRIV (object
);
306 view_clear_load (YELP_VIEW (object
));
308 if (priv
->vadjuster
> 0) {
309 g_signal_handler_disconnect (priv
->vadjustment
, priv
->vadjuster
);
313 if (priv
->hadjuster
> 0) {
314 g_signal_handler_disconnect (priv
->hadjustment
, priv
->hadjuster
);
318 if (priv
->action_group
) {
319 g_object_unref (priv
->action_group
);
320 priv
->action_group
= NULL
;
323 if (priv
->document
) {
324 g_object_unref (priv
->document
);
325 priv
->document
= NULL
;
328 while (priv
->link_actions
) {
329 action_entry_free (priv
->link_actions
->data
);
330 priv
->link_actions
= g_slist_delete_link (priv
->link_actions
, priv
->link_actions
);
333 priv
->back_cur
= NULL
;
334 while (priv
->back_list
) {
335 back_entry_free ((YelpBackEntry
*) priv
->back_list
->data
);
336 priv
->back_list
= g_list_delete_link (priv
->back_list
, priv
->back_list
);
339 G_OBJECT_CLASS (yelp_view_parent_class
)->dispose (object
);
343 yelp_view_finalize (GObject
*object
)
345 YelpViewPrivate
*priv
= GET_PRIV (object
);
347 g_free (priv
->popup_link_uri
);
348 g_free (priv
->popup_link_text
);
349 g_free (priv
->popup_image_uri
);
350 g_free (priv
->popup_code_text
);
352 g_free (priv
->page_id
);
353 g_free (priv
->root_title
);
354 g_free (priv
->page_title
);
355 g_free (priv
->page_desc
);
356 g_free (priv
->page_icon
);
358 g_free (priv
->bogus_uri
);
360 G_OBJECT_CLASS (yelp_view_parent_class
)->finalize (object
);
364 yelp_view_class_init (YelpViewClass
*klass
)
366 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
367 YelpSettings
*settings
= yelp_settings_get_default ();
369 nautilus_sendto
= g_find_program_in_path ("nautilus-sendto");
371 websettings
= webkit_web_settings_new ();
372 g_object_set (websettings
, "enable-universal-access-from-file-uris", TRUE
, NULL
);
373 g_signal_connect (settings
,
375 G_CALLBACK (settings_set_fonts
),
377 settings_set_fonts (settings
);
378 g_signal_connect (settings
,
379 "notify::show-text-cursor",
380 G_CALLBACK (settings_show_text_cursor
),
382 settings_show_text_cursor (settings
);
384 klass
->external_uri
= view_external_uri
;
386 object_class
->dispose
= yelp_view_dispose
;
387 object_class
->finalize
= yelp_view_finalize
;
388 object_class
->get_property
= yelp_view_get_property
;
389 object_class
->set_property
= yelp_view_set_property
;
391 signals
[NEW_VIEW_REQUESTED
] =
392 g_signal_new ("new-view-requested",
393 G_TYPE_FROM_CLASS (klass
),
396 g_cclosure_marshal_VOID__OBJECT
,
397 G_TYPE_NONE
, 1, YELP_TYPE_URI
);
399 signals
[EXTERNAL_URI
] =
400 g_signal_new ("external-uri",
401 G_TYPE_FROM_CLASS (klass
),
403 G_STRUCT_OFFSET (YelpViewClass
, external_uri
),
404 g_signal_accumulator_true_handled
, NULL
,
405 yelp_marshal_BOOLEAN__OBJECT
,
406 G_TYPE_BOOLEAN
, 1, YELP_TYPE_URI
);
409 g_signal_new ("loaded",
410 G_TYPE_FROM_CLASS (klass
),
413 g_cclosure_marshal_VOID__VOID
,
416 g_type_class_add_private (klass
, sizeof (YelpViewPrivate
));
418 g_object_class_install_property (object_class
,
420 g_param_spec_object ("yelp-uri",
422 _("A YelpUri with the current location"),
424 G_PARAM_READWRITE
| G_PARAM_STATIC_NAME
|
425 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
427 g_object_class_install_property (object_class
,
429 g_param_spec_enum ("state",
431 N_("The loading state of the view"),
432 YELP_TYPE_VIEW_STATE
,
433 YELP_VIEW_STATE_BLANK
,
434 G_PARAM_READWRITE
| G_PARAM_STATIC_NAME
|
435 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
437 g_object_class_install_property (object_class
,
439 g_param_spec_string ("page-id",
441 N_("The ID of the root page of the page being viewed"),
444 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
446 g_object_class_install_property (object_class
,
448 g_param_spec_string ("root-title",
450 N_("The title of the root page of the page being viewed"),
453 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
455 g_object_class_install_property (object_class
,
457 g_param_spec_string ("page-title",
459 N_("The title of the page being viewed"),
462 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
464 g_object_class_install_property (object_class
,
466 g_param_spec_string ("page-desc",
467 N_("Page Description"),
468 N_("The description of the page being viewed"),
471 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
473 g_object_class_install_property (object_class
,
475 g_param_spec_string ("page-icon",
477 N_("The icon of the page being viewed"),
480 G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
));
484 yelp_view_get_property (GObject
*object
,
489 YelpViewPrivate
*priv
= GET_PRIV (object
);
494 g_value_set_object (value
, priv
->uri
);
497 g_value_set_string (value
, priv
->page_id
);
499 case PROP_ROOT_TITLE
:
500 g_value_set_string (value
, priv
->root_title
);
502 case PROP_PAGE_TITLE
:
503 g_value_set_string (value
, priv
->page_title
);
506 g_value_set_string (value
, priv
->page_desc
);
510 g_value_set_string (value
, priv
->page_icon
);
512 g_value_set_string (value
, "yelp-page-symbolic");
515 g_value_set_enum (value
, priv
->state
);
518 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
524 yelp_view_set_property (GObject
*object
,
530 YelpViewPrivate
*priv
= GET_PRIV (object
);
535 uri
= g_value_get_object (value
);
536 yelp_view_load_uri (YELP_VIEW (object
), uri
);
537 g_object_unref (uri
);
540 priv
->prevstate
= priv
->state
;
541 priv
->state
= g_value_get_enum (value
);
544 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
549 /******************************************************************************/
554 return (GtkWidget
*) g_object_new (YELP_TYPE_VIEW
, NULL
);
558 yelp_view_load (YelpView
*view
,
561 YelpUri
*yuri
= yelp_uri_new (uri
);
562 yelp_view_load_uri (view
, yuri
);
563 g_object_unref (yuri
);
567 yelp_view_load_uri (YelpView
*view
,
570 YelpViewPrivate
*priv
= GET_PRIV (view
);
572 g_object_set (view
, "state", YELP_VIEW_STATE_LOADING
, NULL
);
574 gtk_action_set_sensitive (gtk_action_group_get_action (priv
->action_group
,
575 "YelpViewGoPrevious"),
577 gtk_action_set_sensitive (gtk_action_group_get_action (priv
->action_group
,
581 if (!yelp_uri_is_resolved (uri
)) {
582 if (priv
->resolve_uri
!= NULL
) {
583 if (priv
->uri_resolved
!= 0) {
584 g_signal_handler_disconnect (priv
->resolve_uri
, priv
->uri_resolved
);
585 priv
->uri_resolved
= 0;
587 g_object_unref (priv
->resolve_uri
);
589 priv
->resolve_uri
= g_object_ref (uri
);
590 priv
->uri_resolved
= g_signal_connect (uri
, "resolved",
591 G_CALLBACK (uri_resolved
),
593 yelp_uri_resolve (uri
);
596 uri_resolved (uri
, view
);
601 yelp_view_load_document (YelpView
*view
,
603 YelpDocument
*document
)
606 YelpViewPrivate
*priv
= GET_PRIV (view
);
608 g_return_if_fail (yelp_uri_is_resolved (uri
));
610 g_object_set (view
, "state", YELP_VIEW_STATE_LOADING
, NULL
);
613 view_clear_load (view
);
615 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
617 g_signal_emit_by_name (view
, "notify::yelp-uri", spec
);
618 g_object_ref (document
);
620 g_object_unref (document
);
621 priv
->document
= document
;
623 view_load_page (view
);
627 yelp_view_get_document (YelpView
*view
)
629 YelpViewPrivate
*priv
= GET_PRIV (view
);
630 return priv
->document
;
634 yelp_view_get_action_group (YelpView
*view
)
636 YelpViewPrivate
*priv
= GET_PRIV (view
);
637 return priv
->action_group
;
640 /******************************************************************************/
643 yelp_view_add_link_action (YelpView
*view
,
645 YelpViewActionValidFunc func
,
648 YelpActionEntry
*entry
;
649 YelpViewPrivate
*priv
= GET_PRIV (view
);
651 entry
= g_new0 (YelpActionEntry
, 1);
652 entry
->action
= g_object_ref (action
);
656 priv
->link_actions
= g_slist_append (priv
->link_actions
, entry
);
660 yelp_view_get_active_link_uri (YelpView
*view
)
662 YelpViewPrivate
*priv
= GET_PRIV (view
);
665 if (g_str_has_prefix (priv
->popup_link_uri
, BOGUS_URI
))
666 uri
= yelp_uri_new_relative (priv
->uri
, priv
->popup_link_uri
+ BOGUS_URI_LEN
);
668 uri
= yelp_uri_new_relative (priv
->uri
, priv
->popup_link_uri
);
674 yelp_view_get_active_link_text (YelpView
*view
)
676 YelpViewPrivate
*priv
= GET_PRIV (view
);
677 return g_strdup (priv
->popup_link_text
);
680 /******************************************************************************/
683 view_external_uri (YelpView
*view
,
686 gchar
*struri
= yelp_uri_get_canonical_uri (uri
);
687 g_app_info_launch_default_for_uri (struri
, NULL
, NULL
);
692 typedef struct _YelpInstallInfo YelpInstallInfo
;
693 struct _YelpInstallInfo
{
699 yelp_install_info_free (YelpInstallInfo
*info
)
701 g_object_unref (info
->view
);
708 view_install_installed (GDBusConnection
*connection
,
710 YelpInstallInfo
*info
)
712 GError
*error
= NULL
;
713 g_dbus_connection_call_finish (connection
, res
, &error
);
715 const gchar
*err
= NULL
;
716 if (error
->domain
== G_DBUS_ERROR
) {
717 if (error
->code
== G_DBUS_ERROR_SERVICE_UNKNOWN
)
718 err
= _("You do not have PackageKit. Package install links require PackageKit.");
720 err
= error
->message
;
723 GtkWidget
*dialog
= gtk_message_dialog_new (NULL
, 0,
727 gtk_dialog_run ((GtkDialog
*) dialog
);
728 gtk_widget_destroy (dialog
);
730 g_error_free (error
);
732 else if (info
->uri
) {
733 gchar
*struri
, *docuri
;
734 YelpViewPrivate
*priv
= GET_PRIV (info
->view
);
735 docuri
= yelp_uri_get_document_uri (priv
->uri
);
736 if (g_str_equal (docuri
, info
->uri
)) {
737 struri
= yelp_uri_get_canonical_uri (priv
->uri
);
738 yelp_view_load (info
->view
, struri
);
744 yelp_install_info_free (info
);
748 view_install_uri (YelpView
*view
,
751 GDBusConnection
*connection
;
753 gboolean help
= FALSE
, ghelp
= FALSE
;
754 GVariantBuilder
*strv
;
755 YelpInstallInfo
*info
;
757 YelpViewPrivate
*priv
= GET_PRIV (view
);
761 gchar
*pkg
, *confirm_search
;
763 if (g_str_has_prefix (uri
, "install-help:")) {
765 pkg
= (gchar
*) uri
+ 13;
767 else if (g_str_has_prefix (uri
, "install-ghelp:")) {
769 pkg
= (gchar
*) uri
+ 14;
771 else if (g_str_has_prefix (uri
, "install:")) {
772 pkg
= (gchar
*) uri
+ 8;
775 connection
= g_bus_get_sync (G_BUS_TYPE_SESSION
, NULL
, NULL
);
776 if (connection
== NULL
) {
777 g_warning ("Unable to connect to dbus: %s", error
->message
);
778 g_error_free (error
);
782 info
= g_new0 (YelpInstallInfo
, 1);
783 info
->view
= g_object_ref (view
);
785 gtkwin
= gtk_widget_get_toplevel (GTK_WIDGET (view
));
786 if (gtkwin
!= NULL
&& gtk_widget_is_toplevel (gtkwin
)) {
787 gdkwin
= gtk_widget_get_window (gtkwin
);
789 xid
= gdk_x11_window_get_xid (gdkwin
);
792 if (priv
->state
== YELP_VIEW_STATE_ERROR
)
793 confirm_search
= "hide-confirm-search";
798 const gchar
* const *datadirs
= g_get_system_data_dirs ();
800 gchar
*docbook
, *fname
;
801 docbook
= g_strconcat (pkg
, ".xml", NULL
);
802 strv
= g_variant_builder_new (G_VARIANT_TYPE ("as"));
803 for (datadirs_i
= 0; datadirs
[datadirs_i
] != NULL
; datadirs_i
++) {
805 fname
= g_build_filename (datadirs
[datadirs_i
], "gnome", "help",
806 pkg
, "C", "index.page", NULL
);
807 g_variant_builder_add (strv
, "s", fname
);
809 fname
= g_build_filename (datadirs
[datadirs_i
], "gnome", "help",
810 pkg
, "C", docbook
, NULL
);
811 g_variant_builder_add (strv
, "s", fname
);
815 fname
= g_build_filename (datadirs
[datadirs_i
], "help", "C",
816 pkg
, "index.page", NULL
);
817 g_variant_builder_add (strv
, "s", fname
);
819 fname
= g_build_filename (datadirs
[datadirs_i
], "help", "C",
820 pkg
, "index.docbook", NULL
);
821 g_variant_builder_add (strv
, "s", fname
);
826 info
->uri
= g_strconcat (ghelp
? "ghelp:" : "help:", pkg
, NULL
);
827 g_dbus_connection_call (connection
,
828 "org.freedesktop.PackageKit",
829 "/org/freedesktop/PackageKit",
830 "org.freedesktop.PackageKit.Modify",
831 "InstallProvideFiles",
832 g_variant_new ("(uass)", xid
, strv
, confirm_search
),
834 G_DBUS_CALL_FLAGS_NONE
,
836 (GAsyncReadyCallback
) view_install_installed
,
838 g_variant_builder_unref (strv
);
843 strv
= g_variant_builder_new (G_VARIANT_TYPE ("as"));
844 pkgs
= g_strsplit (pkg
, ",", 0);
845 for (i
= 0; pkgs
[i
]; i
++)
846 g_variant_builder_add (strv
, "s", pkgs
[i
]);
848 g_dbus_connection_call (connection
,
849 "org.freedesktop.PackageKit",
850 "/org/freedesktop/PackageKit",
851 "org.freedesktop.PackageKit.Modify",
852 "InstallPackageNames",
853 g_variant_new ("(uass)", xid
, strv
, confirm_search
),
855 G_DBUS_CALL_FLAGS_NONE
,
857 (GAsyncReadyCallback
) view_install_installed
,
859 g_variant_builder_unref (strv
);
862 g_object_unref (connection
);
866 view_scrolled (GtkAdjustment
*adjustment
,
869 YelpViewPrivate
*priv
= GET_PRIV (view
);
870 if (priv
->back_cur
== NULL
|| priv
->back_cur
->data
== NULL
)
872 if (adjustment
== priv
->vadjustment
)
873 ((YelpBackEntry
*) priv
->back_cur
->data
)->vadj
= gtk_adjustment_get_value (adjustment
);
874 else if (adjustment
= priv
->hadjustment
)
875 ((YelpBackEntry
*) priv
->back_cur
->data
)->hadj
= gtk_adjustment_get_value (adjustment
);
879 view_set_hadjustment (YelpView
*view
,
883 YelpViewPrivate
*priv
= GET_PRIV (view
);
884 priv
->hadjustment
= gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (view
));
885 if (priv
->hadjuster
> 0)
886 g_signal_handler_disconnect (priv
->hadjustment
, priv
->hadjuster
);
888 if (priv
->hadjustment
)
889 priv
->hadjuster
= g_signal_connect (priv
->hadjustment
, "value-changed",
890 G_CALLBACK (view_scrolled
), view
);
894 view_set_vadjustment (YelpView
*view
,
898 YelpViewPrivate
*priv
= GET_PRIV (view
);
899 priv
->vadjustment
= gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (view
));
900 if (priv
->vadjuster
> 0)
901 g_signal_handler_disconnect (priv
->vadjustment
, priv
->vadjuster
);
903 if (priv
->vadjustment
)
904 priv
->vadjuster
= g_signal_connect (priv
->vadjustment
, "value-changed",
905 G_CALLBACK (view_scrolled
), view
);
909 popup_open_link (GtkMenuItem
*item
,
912 YelpViewPrivate
*priv
= GET_PRIV (view
);
915 if (g_str_has_prefix (priv
->popup_link_uri
, BOGUS_URI
))
916 uri
= yelp_uri_new_relative (priv
->uri
, priv
->popup_link_uri
+ BOGUS_URI_LEN
);
918 uri
= yelp_uri_new_relative (priv
->uri
, priv
->popup_link_uri
);
920 yelp_view_load_uri (view
, uri
);
921 g_object_unref (uri
);
923 g_free (priv
->popup_link_uri
);
924 priv
->popup_link_uri
= NULL
;
926 g_free (priv
->popup_link_text
);
927 priv
->popup_link_text
= NULL
;
931 popup_open_link_new (GtkMenuItem
*item
,
934 YelpViewPrivate
*priv
= GET_PRIV (view
);
937 if (g_str_has_prefix (priv
->popup_link_uri
, BOGUS_URI
))
938 uri
= yelp_uri_new_relative (priv
->uri
, priv
->popup_link_uri
+ BOGUS_URI_LEN
);
940 uri
= yelp_uri_new_relative (priv
->uri
, priv
->popup_link_uri
);
942 g_free (priv
->popup_link_uri
);
943 priv
->popup_link_uri
= NULL
;
945 g_free (priv
->popup_link_text
);
946 priv
->popup_link_text
= NULL
;
948 g_signal_emit (view
, signals
[NEW_VIEW_REQUESTED
], 0, uri
);
949 g_object_unref (uri
);
953 popup_copy_link (GtkMenuItem
*item
,
956 YelpViewPrivate
*priv
= GET_PRIV (view
);
957 gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (view
), GDK_SELECTION_CLIPBOARD
),
958 priv
->popup_link_uri
,
962 typedef struct _YelpSaveData YelpSaveData
;
963 struct _YelpSaveData
{
971 file_copied (GFile
*file
,
975 GError
*error
= NULL
;
976 if (!g_file_copy_finish (file
, res
, &error
)) {
977 GtkWidget
*dialog
= gtk_message_dialog_new (gtk_widget_get_visible (GTK_WIDGET (data
->window
)) ? data
->window
: NULL
,
978 GTK_DIALOG_DESTROY_WITH_PARENT
,
981 "%s", error
->message
);
982 gtk_dialog_run (GTK_DIALOG (dialog
));
983 gtk_widget_destroy (dialog
);
985 g_object_unref (data
->orig
);
986 g_object_unref (data
->dest
);
987 g_object_unref (data
->view
);
988 g_object_unref (data
->window
);
992 popup_save_image (GtkMenuItem
*item
,
996 GtkWidget
*dialog
, *window
;
999 YelpViewPrivate
*priv
= GET_PRIV (view
);
1001 for (window
= gtk_widget_get_parent (GTK_WIDGET (view
));
1002 window
&& !GTK_IS_WINDOW (window
);
1003 window
= gtk_widget_get_parent (window
));
1005 data
= g_new0 (YelpSaveData
, 1);
1006 data
->orig
= g_file_new_for_uri (priv
->popup_image_uri
);
1007 data
->view
= g_object_ref (view
);
1008 data
->window
= g_object_ref (window
);
1009 g_free (priv
->popup_image_uri
);
1010 priv
->popup_image_uri
= NULL
;
1012 dialog
= gtk_file_chooser_dialog_new (_("Save Image"),
1013 GTK_WINDOW (window
),
1014 GTK_FILE_CHOOSER_ACTION_SAVE
,
1015 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1016 GTK_STOCK_SAVE
, GTK_RESPONSE_OK
,
1018 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
), TRUE
);
1019 basename
= g_file_get_basename (data
->orig
);
1020 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), basename
);
1022 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
),
1023 g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP
));
1025 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
1027 if (res
== GTK_RESPONSE_OK
) {
1028 data
->dest
= gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog
));
1029 g_file_copy_async (data
->orig
, data
->dest
,
1030 G_FILE_COPY_OVERWRITE
,
1033 (GAsyncReadyCallback
) file_copied
,
1037 g_object_unref (data
->orig
);
1038 g_object_unref (data
->view
);
1039 g_object_unref (data
->window
);
1043 gtk_widget_destroy (dialog
);
1047 popup_send_image (GtkMenuItem
*item
,
1052 GAppLaunchContext
*context
;
1053 GError
*error
= NULL
;
1054 YelpViewPrivate
*priv
= GET_PRIV (view
);
1056 command
= g_strdup_printf ("%s %s", nautilus_sendto
, priv
->popup_image_uri
);
1057 context
= (GAppLaunchContext
*) gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (item
)));
1059 app
= g_app_info_create_from_commandline (command
, NULL
, 0, &error
);
1061 g_app_info_launch (app
, NULL
, context
, &error
);
1062 g_object_unref (app
);
1066 g_debug ("Could not launch nautilus-sendto: %s", error
->message
);
1067 g_error_free (error
);
1070 g_object_unref (context
);
1072 g_free (priv
->popup_image_uri
);
1073 priv
->popup_image_uri
= NULL
;
1077 popup_copy_code (GtkMenuItem
*item
,
1080 YelpViewPrivate
*priv
= GET_PRIV (view
);
1081 GtkClipboard
*clipboard
= gtk_clipboard_get (GDK_SELECTION_CLIPBOARD
);
1082 gchar
*content
= webkit_dom_node_get_text_content (priv
->popup_code_node
);
1083 gtk_clipboard_set_text (clipboard
, content
, -1);
1088 popup_save_code (GtkMenuItem
*item
,
1091 YelpViewPrivate
*priv
= GET_PRIV (view
);
1092 GtkWidget
*dialog
, *window
;
1095 g_free (priv
->popup_code_text
);
1096 priv
->popup_code_text
= webkit_dom_node_get_text_content (priv
->popup_code_node
);
1097 if (!g_str_has_suffix (priv
->popup_code_text
, "\n")) {
1098 gchar
*tmp
= g_strconcat (priv
->popup_code_text
, "\n", NULL
);
1099 g_free (priv
->popup_code_text
);
1100 priv
->popup_code_text
= tmp
;
1103 for (window
= gtk_widget_get_parent (GTK_WIDGET (view
));
1104 window
&& !GTK_IS_WINDOW (window
);
1105 window
= gtk_widget_get_parent (window
));
1107 dialog
= gtk_file_chooser_dialog_new (_("Save Code"),
1108 GTK_WINDOW (window
),
1109 GTK_FILE_CHOOSER_ACTION_SAVE
,
1110 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1111 GTK_STOCK_SAVE
, GTK_RESPONSE_OK
,
1113 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
), TRUE
);
1114 if (priv
->popup_code_title
) {
1115 gchar
*filename
= webkit_dom_node_get_text_content (priv
->popup_code_title
);
1116 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), filename
);
1119 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
),
1120 g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS
));
1122 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
1124 if (res
== GTK_RESPONSE_OK
) {
1125 GError
*error
= NULL
;
1126 GFile
*file
= gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog
));
1127 GFileOutputStream
*stream
= g_file_replace (file
, NULL
, FALSE
,
1131 if (stream
== NULL
) {
1132 GtkWidget
*dialog
= gtk_message_dialog_new (gtk_widget_get_visible (window
) ? GTK_WINDOW (window
) : NULL
,
1133 GTK_DIALOG_DESTROY_WITH_PARENT
,
1136 "%s", error
->message
);
1137 gtk_dialog_run (GTK_DIALOG (dialog
));
1138 gtk_widget_destroy (dialog
);
1139 g_error_free (error
);
1142 /* FIXME: we should do this async */
1143 GDataOutputStream
*datastream
= g_data_output_stream_new (G_OUTPUT_STREAM (stream
));
1144 if (!g_data_output_stream_put_string (datastream
, priv
->popup_code_text
, NULL
, &error
)) {
1145 GtkWidget
*dialog
= gtk_message_dialog_new (gtk_widget_get_visible (window
) ? GTK_WINDOW (window
) : NULL
,
1146 GTK_DIALOG_DESTROY_WITH_PARENT
,
1149 "%s", error
->message
);
1150 gtk_dialog_run (GTK_DIALOG (dialog
));
1151 gtk_widget_destroy (dialog
);
1152 g_error_free (error
);
1154 g_object_unref (datastream
);
1156 g_object_unref (file
);
1159 priv
->popup_code_node
= NULL
;
1160 priv
->popup_code_title
= NULL
;
1161 g_free (priv
->popup_code_text
);
1162 priv
->popup_code_text
= NULL
;
1164 gtk_widget_destroy (dialog
);
1168 view_populate_popup (YelpView
*view
,
1172 WebKitHitTestResult
*result
;
1173 WebKitHitTestResultContext context
;
1175 YelpViewPrivate
*priv
= GET_PRIV (view
);
1178 WebKitDOMNode
*node
, *cur
, *link_node
= NULL
, *code_node
= NULL
, *code_title_node
= NULL
;
1180 children
= gtk_container_get_children (GTK_CONTAINER (menu
));
1182 gtk_container_remove (GTK_CONTAINER (menu
),
1183 GTK_WIDGET (children
->data
));
1184 children
= children
->next
;
1186 g_list_free (children
);
1188 event
= gtk_get_current_event ();
1190 result
= webkit_web_view_get_hit_test_result (WEBKIT_WEB_VIEW (view
), (GdkEventButton
*) event
);
1191 g_object_get (result
,
1192 "context", &context
,
1193 "inner-node", &node
,
1195 for (cur
= node
; cur
!= NULL
; cur
= webkit_dom_node_get_parent_node (cur
)) {
1196 if (WEBKIT_DOM_IS_ELEMENT (cur
) &&
1197 webkit_dom_element_webkit_matches_selector ((WebKitDOMElement
*) cur
,
1201 if (WEBKIT_DOM_IS_ELEMENT (cur
) &&
1202 webkit_dom_element_webkit_matches_selector ((WebKitDOMElement
*) cur
,
1203 "div.code", NULL
)) {
1204 WebKitDOMNode
*title
;
1205 code_node
= (WebKitDOMNode
*)
1206 webkit_dom_element_query_selector ((WebKitDOMElement
*) cur
,
1207 "pre.contents", NULL
);
1208 title
= webkit_dom_node_get_parent_node (cur
);
1209 if (title
!= NULL
&& WEBKIT_DOM_IS_ELEMENT (title
) &&
1210 webkit_dom_element_webkit_matches_selector ((WebKitDOMElement
*) title
,
1211 "div.contents", NULL
)) {
1212 title
= webkit_dom_node_get_previous_sibling (title
);
1213 if (title
!= NULL
&& WEBKIT_DOM_IS_ELEMENT (title
) &&
1214 webkit_dom_element_webkit_matches_selector ((WebKitDOMElement
*) title
,
1215 "div.title", NULL
)) {
1216 code_title_node
= title
;
1222 if (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK
) {
1224 g_object_get (result
, "link-uri", &uri
, NULL
);
1225 g_free (priv
->popup_link_uri
);
1226 priv
->popup_link_uri
= uri
;
1228 g_free (priv
->popup_link_text
);
1229 priv
->popup_link_text
= NULL
;
1230 if (link_node
!= NULL
) {
1231 WebKitDOMNode
*child
;
1236 child
= (WebKitDOMNode
*)
1237 webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (link_node
),
1238 "span.title", NULL
);
1240 priv
->popup_link_text
= webkit_dom_node_get_text_content (child
);
1242 if (priv
->popup_link_text
== NULL
)
1243 priv
->popup_link_text
= webkit_dom_node_get_text_content (link_node
);
1245 tmp
= g_new0 (gchar
, strlen(priv
->popup_link_text
) + 1);
1247 for (i
= 0, tmpi
= 0; priv
->popup_link_text
[i
] != '\0'; i
++) {
1248 if (priv
->popup_link_text
[i
] == ' ' || priv
->popup_link_text
[i
] == '\n') {
1256 tmp
[tmpi
] = priv
->popup_link_text
[i
];
1262 g_free (priv
->popup_link_text
);
1263 priv
->popup_link_text
= tmp
;
1266 priv
->popup_link_text
= g_strdup (uri
);
1269 if (g_str_has_prefix (priv
->popup_link_uri
, "mailto:")) {
1270 gchar
*label
= g_strdup_printf (_("Send email to %s"),
1271 priv
->popup_link_uri
+ 7);
1272 /* Not using a mnemonic because underscores are common in email
1273 * addresses, and we'd have to escape them. There doesn't seem
1274 * to be a quick GTK+ function for this. In practice, there will
1275 * probably only be one menu item for mailto link popups anyway,
1276 * so the mnemonic's not that big of a deal.
1278 item
= gtk_menu_item_new_with_label (label
);
1279 g_signal_connect (item
, "activate",
1280 G_CALLBACK (popup_open_link
), view
);
1281 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1284 else if (g_str_has_prefix (priv
->popup_link_uri
, "install:")) {
1285 item
= gtk_menu_item_new_with_mnemonic (_("_Install Packages"));
1286 g_signal_connect (item
, "activate",
1287 G_CALLBACK (popup_open_link
), view
);
1288 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1293 item
= gtk_menu_item_new_with_mnemonic (_("_Open Link"));
1294 g_signal_connect (item
, "activate",
1295 G_CALLBACK (popup_open_link
), view
);
1296 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1298 if (g_str_has_prefix (priv
->popup_link_uri
, "http://") ||
1299 g_str_has_prefix (priv
->popup_link_uri
, "https://")) {
1300 item
= gtk_menu_item_new_with_mnemonic (_("_Copy Link Location"));
1301 g_signal_connect (item
, "activate",
1302 G_CALLBACK (popup_copy_link
), view
);
1303 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1306 item
= gtk_menu_item_new_with_mnemonic (_("Open Link in New _Window"));
1307 g_signal_connect (item
, "activate",
1308 G_CALLBACK (popup_open_link_new
), view
);
1309 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1312 for (cur
= priv
->link_actions
; cur
!= NULL
; cur
= cur
->next
) {
1314 YelpActionEntry
*entry
= (YelpActionEntry
*) cur
->data
;
1315 if (entry
->func
== NULL
)
1318 add
= (* entry
->func
) (view
, entry
->action
,
1319 priv
->popup_link_uri
,
1322 item
= gtk_action_create_menu_item (entry
->action
);
1323 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1329 item
= gtk_action_create_menu_item (gtk_action_group_get_action (priv
->action_group
,
1331 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1332 item
= gtk_action_create_menu_item (gtk_action_group_get_action (priv
->action_group
,
1333 "YelpViewGoForward"));
1334 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1337 if ((context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE
) ||
1338 (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA
)) {
1339 /* This doesn't currently work for video with automatic controls,
1340 * because WebKit puts the hit test on the div with the controls.
1342 gboolean image
= context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE
;
1344 g_object_get (result
, image
? "image-uri" : "media-uri", &uri
, NULL
);
1345 g_free (priv
->popup_image_uri
);
1346 if (g_str_has_prefix (uri
, BOGUS_URI
)) {
1347 priv
->popup_image_uri
= yelp_uri_locate_file_uri (priv
->uri
, uri
+ BOGUS_URI_LEN
);
1351 priv
->popup_image_uri
= uri
;
1354 item
= gtk_separator_menu_item_new ();
1355 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1358 item
= gtk_menu_item_new_with_mnemonic (_("_Save Image As..."));
1360 item
= gtk_menu_item_new_with_mnemonic (_("_Save Video As..."));
1361 g_signal_connect (item
, "activate",
1362 G_CALLBACK (popup_save_image
), view
);
1363 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1365 if (nautilus_sendto
) {
1367 item
= gtk_menu_item_new_with_mnemonic (_("S_end Image To..."));
1369 item
= gtk_menu_item_new_with_mnemonic (_("S_end Video To..."));
1370 g_signal_connect (item
, "activate",
1371 G_CALLBACK (popup_send_image
), view
);
1372 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1376 if (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION
) {
1377 item
= gtk_separator_menu_item_new ();
1378 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1380 item
= gtk_menu_item_new_with_mnemonic (_("_Copy Text"));
1381 g_signal_connect_swapped (item
, "activate",
1382 G_CALLBACK (webkit_web_view_copy_clipboard
), view
);
1383 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1386 if (code_node
!= NULL
) {
1387 item
= gtk_separator_menu_item_new ();
1388 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1390 priv
->popup_code_node
= code_node
;
1391 priv
->popup_code_title
= code_title_node
;
1393 item
= gtk_menu_item_new_with_mnemonic (_("C_opy Code Block"));
1394 g_signal_connect (item
, "activate",
1395 G_CALLBACK (popup_copy_code
), view
);
1396 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1398 item
= gtk_menu_item_new_with_mnemonic (_("Save Code _Block As..."));
1399 g_signal_connect (item
, "activate",
1400 G_CALLBACK (popup_save_code
), view
);
1401 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1404 g_object_unref (result
);
1405 gdk_event_free (event
);
1406 gtk_widget_show_all (GTK_WIDGET (menu
));
1410 view_script_alert (YelpView
*view
,
1411 WebKitWebFrame
*frame
,
1415 printf ("\n\n===ALERT===\n%s\n\n", message
);
1419 view_navigation_requested (WebKitWebView
*view
,
1420 WebKitWebFrame
*frame
,
1421 WebKitNetworkRequest
*request
,
1422 WebKitWebNavigationAction
*action
,
1423 WebKitWebPolicyDecision
*decision
,
1426 const gchar
*requri
= webkit_network_request_get_uri (request
);
1427 YelpViewPrivate
*priv
= GET_PRIV (view
);
1430 if (priv
->bogus_uri
&&
1431 g_str_has_prefix (requri
, priv
->bogus_uri
) &&
1432 requri
[strlen(priv
->bogus_uri
)] == '#') {
1433 gchar
*tmp
= g_strconcat("xref:", requri
+ strlen(priv
->bogus_uri
), NULL
);
1434 uri
= yelp_uri_new_relative (priv
->uri
, tmp
);
1437 else if (g_str_has_prefix (requri
, BOGUS_URI
)) {
1438 uri
= yelp_uri_new_relative (priv
->uri
, requri
+ BOGUS_URI_LEN
);
1441 uri
= yelp_uri_new_relative (priv
->uri
, requri
);
1443 webkit_web_policy_decision_ignore (decision
);
1445 yelp_view_load_uri ((YelpView
*) view
, uri
);
1446 g_object_unref (uri
);
1452 view_resource_request (WebKitWebView
*view
,
1453 WebKitWebFrame
*frame
,
1454 WebKitWebResource
*resource
,
1455 WebKitNetworkRequest
*request
,
1456 WebKitNetworkResponse
*response
,
1459 YelpViewPrivate
*priv
= GET_PRIV (view
);
1460 const gchar
*requri
= webkit_network_request_get_uri (request
);
1464 if (!g_str_has_prefix (requri
, BOGUS_URI
))
1467 /* We get this signal for the page itself. Ignore. */
1468 if (g_str_equal (requri
, priv
->bogus_uri
))
1471 newpath
= yelp_uri_locate_file_uri (priv
->uri
, requri
+ BOGUS_URI_LEN
);
1472 if (newpath
!= NULL
) {
1473 webkit_network_request_set_uri (request
, newpath
);
1477 webkit_network_request_set_uri (request
, "about:blank");
1482 view_document_loaded (WebKitWebView
*view
,
1483 WebKitWebFrame
*frame
,
1486 YelpViewPrivate
*priv
= GET_PRIV (view
);
1487 gchar
*search_terms
;
1489 search_terms
= yelp_uri_get_query (priv
->uri
, "terms");
1492 WebKitDOMDocument
*doc
;
1493 WebKitDOMElement
*body
, *link
;
1494 doc
= webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view
));
1495 body
= webkit_dom_document_query_selector (doc
, "div.body", NULL
);
1497 gchar
*tmp
, *uri
, *txt
;
1498 link
= webkit_dom_document_create_element (doc
, "a", NULL
);
1499 webkit_dom_element_set_attribute (link
, "class", "fullsearch", NULL
);
1500 tmp
= g_uri_escape_string (search_terms
, NULL
, FALSE
);
1501 uri
= g_strconcat ("xref:search=", tmp
, NULL
);
1502 webkit_dom_element_set_attribute (link
, "href", uri
, NULL
);
1505 txt
= g_strdup_printf (_("See all search results for “%s”"),
1507 webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (link
), txt
, NULL
);
1509 webkit_dom_node_insert_before (WEBKIT_DOM_NODE (body
),
1510 WEBKIT_DOM_NODE (link
),
1511 webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body
)),
1514 g_free (search_terms
);
1519 view_print (GtkAction
*action
, YelpView
*view
)
1521 webkit_web_frame_print (webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (view
)));
1525 view_history_action (GtkAction
*action
,
1529 YelpViewPrivate
*priv
= GET_PRIV (view
);
1531 if (priv
->back_cur
== NULL
)
1534 if (g_str_equal (gtk_action_get_name (action
), "YelpViewGoBack"))
1535 newcur
= priv
->back_cur
->next
;
1537 newcur
= priv
->back_cur
->prev
;
1542 priv
->back_cur
= newcur
;
1544 if (priv
->back_cur
->data
== NULL
)
1547 priv
->back_load
= TRUE
;
1548 yelp_view_load_uri (view
, ((YelpBackEntry
*) priv
->back_cur
->data
)->uri
);
1549 priv
->vadjust
= ((YelpBackEntry
*) priv
->back_cur
->data
)->vadj
;
1550 priv
->hadjust
= ((YelpBackEntry
*) priv
->back_cur
->data
)->hadj
;
1554 view_navigation_action (GtkAction
*action
,
1557 YelpViewPrivate
*priv
= GET_PRIV (view
);
1558 gchar
*page_id
, *new_id
, *xref
;
1561 page_id
= yelp_uri_get_page_id (priv
->uri
);
1563 if (g_str_equal (gtk_action_get_name (action
), "YelpViewGoPrevious"))
1564 new_id
= yelp_document_get_prev_id (priv
->document
, page_id
);
1566 new_id
= yelp_document_get_next_id (priv
->document
, page_id
);
1568 /* Just in case we screwed up somewhere */
1569 if (new_id
== NULL
) {
1570 gtk_action_set_sensitive (action
, FALSE
);
1574 xref
= g_strconcat ("xref:", new_id
, NULL
);
1575 new_uri
= yelp_uri_new_relative (priv
->uri
, xref
);
1576 yelp_view_load_uri (view
, new_uri
);
1580 g_object_unref (new_uri
);
1584 view_clear_load (YelpView
*view
)
1586 YelpViewPrivate
*priv
= GET_PRIV (view
);
1588 if (priv
->resolve_uri
!= NULL
) {
1589 if (priv
->uri_resolved
!= 0) {
1590 g_signal_handler_disconnect (priv
->resolve_uri
, priv
->uri_resolved
);
1591 priv
->uri_resolved
= 0;
1593 g_object_unref (priv
->resolve_uri
);
1595 priv
->resolve_uri
= NULL
;
1598 g_object_unref (priv
->uri
);
1602 if (priv
->cancellable
) {
1603 g_cancellable_cancel (priv
->cancellable
);
1604 priv
->cancellable
= NULL
;
1609 view_load_page (YelpView
*view
)
1611 YelpViewPrivate
*priv
= GET_PRIV (view
);
1614 debug_print (DB_FUNCTION
, "entering\n");
1616 g_return_if_fail (priv
->cancellable
== NULL
);
1618 if (priv
->document
== NULL
) {
1621 /* FIXME: and if priv->uri is NULL? */
1622 docuri
= yelp_uri_get_document_uri (priv
->uri
);
1623 /* FIXME: CANT_READ isn't right */
1625 error
= g_error_new (YELP_ERROR
, YELP_ERROR_CANT_READ
,
1626 _("Could not load a document for ‘%s’"),
1631 error
= g_error_new (YELP_ERROR
, YELP_ERROR_CANT_READ
,
1632 _("Could not load a document"));
1634 view_show_error_page (view
, error
);
1635 g_error_free (error
);
1639 page_id
= yelp_uri_get_page_id (priv
->uri
);
1640 priv
->cancellable
= g_cancellable_new ();
1641 yelp_document_request_page (priv
->document
,
1644 (YelpDocumentCallback
) document_callback
,
1650 view_show_error_page (YelpView
*view
,
1653 YelpViewPrivate
*priv
= GET_PRIV (view
);
1654 static const gchar
*errorpage
=
1656 "<style type='text/css'>"
1660 " background-color: %s;"
1662 "p { margin: 1em 0 0 0; }\n"
1665 " border-color: %s;"
1666 " border-top: solid 1px;"
1667 " border-bottom: solid 1px;"
1668 " background-color: %s;"
1670 "div.note div.inner {"
1671 " margin: 0; padding: 0;"
1672 " background-image: url(%s);"
1673 " background-position: %s top;"
1674 " background-repeat: no-repeat;"
1675 " min-height: %ipx;"
1677 "div.note div.contents {"
1680 "div.note div.title {"
1682 " margin-bottom: 0.2em;"
1683 " font-weight: bold;"
1686 "a { color: %s; text-decoration: none; }\n"
1689 "<div class='note'><div class='inner'>"
1690 "%s<div class='contents'>%s%s</div>"
1693 YelpSettings
*settings
= yelp_settings_get_default ();
1694 gchar
*page
, *title
= NULL
, *link
= NULL
, *title_m
, *content_beg
, *content_end
;
1695 gchar
*textcolor
, *bgcolor
, *noteborder
, *notebg
, *titlecolor
, *noteicon
, *linkcolor
;
1698 gboolean doc404
= FALSE
;
1699 const gchar
*left
= (gtk_widget_get_direction((GtkWidget
*) view
) == GTK_TEXT_DIR_RTL
) ? "right" : "left";
1701 if (priv
->uri
&& yelp_uri_get_document_type (priv
->uri
) == YELP_URI_DOCUMENT_TYPE_NOT_FOUND
)
1703 if (error
->domain
== YELP_ERROR
)
1704 switch (error
->code
) {
1705 case YELP_ERROR_NOT_FOUND
:
1707 title
= _("Document Not Found");
1709 title
= _("Page Not Found");
1711 case YELP_ERROR_CANT_READ
:
1712 title
= _("Cannot Read");
1718 title
= _("Unknown Error");
1719 title_m
= g_markup_printf_escaped ("<div class='title'>%s</div>", title
);
1721 content_beg
= g_markup_printf_escaped ("<p>%s</p>", error
->message
);
1724 gchar
*struri
= yelp_uri_get_document_uri (priv
->uri
);
1726 gchar
*pkg
= NULL
, *scheme
= NULL
;
1727 if (g_str_has_prefix (struri
, "help:")) {
1731 else if (g_str_has_prefix (struri
, "ghelp:")) {
1736 content_end
= g_markup_printf_escaped ("<p><a href='install-%s:%s'>%s</a></p>",
1738 _("Search for packages containing this document."));
1742 textcolor
= yelp_settings_get_color (settings
, YELP_SETTINGS_COLOR_TEXT
);
1743 bgcolor
= yelp_settings_get_color (settings
, YELP_SETTINGS_COLOR_BASE
);
1744 noteborder
= yelp_settings_get_color (settings
, YELP_SETTINGS_COLOR_RED_BORDER
);
1745 notebg
= yelp_settings_get_color (settings
, YELP_SETTINGS_COLOR_YELLOW_BASE
);
1746 titlecolor
= yelp_settings_get_color (settings
, YELP_SETTINGS_COLOR_TEXT_LIGHT
);
1747 linkcolor
= yelp_settings_get_color (settings
, YELP_SETTINGS_COLOR_LINK
);
1748 noteicon
= yelp_settings_get_icon (settings
, YELP_SETTINGS_ICON_WARNING
);
1749 iconsize
= yelp_settings_get_icon_size (settings
) + 6;
1751 page
= g_strdup_printf (errorpage
,
1752 textcolor
, bgcolor
, noteborder
, notebg
, noteicon
,
1753 left
, iconsize
, left
, iconsize
, left
, iconsize
,
1754 titlecolor
, linkcolor
, title_m
, content_beg
,
1755 (content_end
!= NULL
) ? content_end
: "");
1757 g_object_set (view
, "state", YELP_VIEW_STATE_ERROR
, NULL
);
1760 g_free (priv
->root_title
);
1761 priv
->root_title
= g_strdup (title
);
1762 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
1764 g_signal_emit_by_name (view
, "notify::root-title", spec
);
1765 g_free (priv
->page_id
);
1766 priv
->page_id
= g_strdup ("index");
1767 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
1769 g_signal_emit_by_name (view
, "notify::page-id", spec
);
1772 g_free (priv
->page_title
);
1773 priv
->page_title
= g_strdup (title
);
1774 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
1776 g_signal_emit_by_name (view
, "notify::page-title", spec
);
1778 g_free (priv
->page_desc
);
1779 priv
->page_desc
= NULL
;
1781 priv
->page_desc
= yelp_uri_get_canonical_uri (priv
->uri
);
1782 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
1784 g_signal_emit_by_name (view
, "notify::page-desc", spec
);
1786 g_free (priv
->page_icon
);
1787 priv
->page_icon
= g_strdup ("dialog-warning");
1788 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
1790 g_signal_emit_by_name (view
, "notify::page-icon", spec
);
1792 g_signal_emit (view
, signals
[LOADED
], 0);
1793 g_signal_handler_block (view
, priv
->navigation_requested
);
1794 webkit_web_view_load_string (WEBKIT_WEB_VIEW (view
),
1799 g_signal_handler_unblock (view
, priv
->navigation_requested
);
1801 g_free (content_beg
);
1802 if (content_end
!= NULL
)
1803 g_free (content_end
);
1809 settings_set_fonts (YelpSettings
*settings
)
1814 g_object_set (websettings
,
1815 "default-encoding", "utf-8",
1816 "enable-private-browsing", TRUE
,
1819 family
= yelp_settings_get_font_family (settings
,
1820 YELP_SETTINGS_FONT_VARIABLE
);
1821 size
= yelp_settings_get_font_size (settings
,
1822 YELP_SETTINGS_FONT_VARIABLE
);
1823 g_object_set (websettings
,
1824 "default-font-family", family
,
1825 "sans-serif-font-family", family
,
1826 "default-font-size", size
,
1830 family
= yelp_settings_get_font_family (settings
,
1831 YELP_SETTINGS_FONT_FIXED
);
1832 size
= yelp_settings_get_font_size (settings
,
1833 YELP_SETTINGS_FONT_FIXED
);
1834 g_object_set (websettings
,
1835 "monospace-font-family", family
,
1836 "default-monospace-font-size", size
,
1842 settings_show_text_cursor (YelpSettings
*settings
)
1844 g_object_set (websettings
,
1845 "enable-caret-browsing",
1846 yelp_settings_get_show_text_cursor (settings
),
1850 /******************************************************************************/
1853 uri_resolved (YelpUri
*uri
,
1856 YelpViewPrivate
*priv
= GET_PRIV (view
);
1857 YelpDocument
*document
;
1858 YelpBackEntry
*back
;
1860 GSList
*proxies
, *cur
;
1861 GError
*error
= NULL
;
1865 if (yelp_uri_get_document_type (uri
) != YELP_URI_DOCUMENT_TYPE_EXTERNAL
) {
1867 view_clear_load (view
);
1871 switch (yelp_uri_get_document_type (uri
)) {
1872 case YELP_URI_DOCUMENT_TYPE_EXTERNAL
:
1873 g_object_set (view
, "state", priv
->prevstate
, NULL
);
1874 struri
= yelp_uri_get_canonical_uri (uri
);
1875 if (g_str_has_prefix (struri
, "install:") ||
1876 g_str_has_prefix (struri
, "install-ghelp:") ||
1877 g_str_has_prefix (struri
, "install-help:")) {
1878 view_install_uri (view
, struri
);
1882 g_signal_emit (view
, signals
[EXTERNAL_URI
], 0, uri
, &result
);
1886 case YELP_URI_DOCUMENT_TYPE_NOT_FOUND
:
1887 struri
= yelp_uri_get_canonical_uri (uri
);
1888 if (struri
!= NULL
) {
1889 error
= g_error_new (YELP_ERROR
, YELP_ERROR_NOT_FOUND
,
1890 _("The URI ‘%s’ does not point to a valid page."),
1895 error
= g_error_new (YELP_ERROR
, YELP_ERROR_NOT_FOUND
,
1896 _("The URI does not point to a valid page."));
1899 case YELP_URI_DOCUMENT_TYPE_ERROR
:
1900 struri
= yelp_uri_get_canonical_uri (uri
);
1901 error
= g_error_new (YELP_ERROR
, YELP_ERROR_PROCESSING
,
1902 _("The URI ‘%s’ could not be parsed."),
1910 if (error
== NULL
) {
1911 document
= yelp_document_get_for_uri (uri
);
1913 g_object_unref (priv
->document
);
1914 priv
->document
= document
;
1917 if (priv
->document
!= NULL
) {
1918 g_object_unref (priv
->document
);
1919 priv
->document
= NULL
;
1923 if (!priv
->back_load
) {
1924 back
= g_new0 (YelpBackEntry
, 1);
1925 back
->uri
= g_object_ref (uri
);
1926 while (priv
->back_list
!= priv
->back_cur
) {
1927 back_entry_free ((YelpBackEntry
*) priv
->back_list
->data
);
1928 priv
->back_list
= g_list_delete_link (priv
->back_list
, priv
->back_list
);
1930 priv
->back_list
= g_list_prepend (priv
->back_list
, back
);
1931 priv
->back_cur
= priv
->back_list
;
1933 priv
->back_load
= FALSE
;
1935 action
= gtk_action_group_get_action (priv
->action_group
, "YelpViewGoBack");
1936 gtk_action_set_sensitive (action
, FALSE
);
1937 proxies
= gtk_action_get_proxies (action
);
1938 if (priv
->back_cur
->next
&& priv
->back_cur
->next
->data
) {
1939 gchar
*tooltip
= "";
1940 back
= priv
->back_cur
->next
->data
;
1942 gtk_action_set_sensitive (action
, TRUE
);
1943 if (back
->title
&& back
->desc
) {
1945 color
= yelp_settings_get_color (yelp_settings_get_default (),
1946 YELP_SETTINGS_COLOR_TEXT_LIGHT
);
1947 tooltip
= g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
1948 back
->title
, color
, back
->desc
);
1951 else if (back
->title
)
1952 tooltip
= g_markup_printf_escaped ("<span size='larger'>%s</span>",
1954 /* Can't seem to use markup on GtkAction tooltip */
1955 for (cur
= proxies
; cur
!= NULL
; cur
= cur
->next
)
1956 gtk_widget_set_tooltip_markup (GTK_WIDGET (cur
->data
), tooltip
);
1959 for (cur
= proxies
; cur
!= NULL
; cur
= cur
->next
)
1960 gtk_widget_set_tooltip_text (GTK_WIDGET (cur
->data
), "");
1963 action
= gtk_action_group_get_action (priv
->action_group
, "YelpViewGoForward");
1964 gtk_action_set_sensitive (action
, FALSE
);
1965 proxies
= gtk_action_get_proxies (action
);
1966 if (priv
->back_cur
->prev
&& priv
->back_cur
->prev
->data
) {
1967 gchar
*tooltip
= "";
1968 back
= priv
->back_cur
->prev
->data
;
1970 gtk_action_set_sensitive (action
, TRUE
);
1971 if (back
->title
&& back
->desc
) {
1973 color
= yelp_settings_get_color (yelp_settings_get_default (),
1974 YELP_SETTINGS_COLOR_TEXT_LIGHT
);
1975 tooltip
= g_markup_printf_escaped ("<span size='larger'>%s</span>\n<span color='%s'>%s</span>",
1976 back
->title
, color
, back
->desc
);
1979 else if (back
->title
)
1980 tooltip
= g_markup_printf_escaped ("<span size='larger'>%s</span>",
1982 /* Can't seem to use markup on GtkAction tooltip */
1983 for (cur
= proxies
; cur
!= NULL
; cur
= cur
->next
)
1984 gtk_widget_set_tooltip_markup (GTK_WIDGET (cur
->data
), tooltip
);
1987 for (cur
= proxies
; cur
!= NULL
; cur
= cur
->next
)
1988 gtk_widget_set_tooltip_text (GTK_WIDGET (cur
->data
), "");
1991 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
1993 g_signal_emit_by_name (view
, "notify::yelp-uri", spec
);
1995 g_free (priv
->page_id
);
1996 priv
->page_id
= NULL
;
1997 if (priv
->uri
!= NULL
)
1998 priv
->page_id
= yelp_uri_get_page_id (priv
->uri
);
1999 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2001 g_signal_emit_by_name (view
, "notify::page-id", spec
);
2003 g_free (priv
->root_title
);
2004 g_free (priv
->page_title
);
2005 g_free (priv
->page_desc
);
2006 g_free (priv
->page_icon
);
2007 priv
->root_title
= NULL
;
2008 priv
->page_title
= NULL
;
2009 priv
->page_desc
= NULL
;
2010 priv
->page_icon
= NULL
;
2012 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2014 g_signal_emit_by_name (view
, "notify::root-title", spec
);
2016 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2018 g_signal_emit_by_name (view
, "notify::page-title", spec
);
2020 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2022 g_signal_emit_by_name (view
, "notify::page-desc", spec
);
2024 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2026 g_signal_emit_by_name (view
, "notify::page-icon", spec
);
2029 view_load_page (view
);
2031 view_show_error_page (view
, error
);
2032 g_error_free (error
);
2037 document_callback (YelpDocument
*document
,
2038 YelpDocumentSignal signal
,
2042 YelpViewPrivate
*priv
= GET_PRIV (view
);
2044 debug_print (DB_FUNCTION
, "entering\n");
2046 if (signal
== YELP_DOCUMENT_SIGNAL_INFO
) {
2047 gchar
*prev_id
, *next_id
, *real_id
;
2049 YelpBackEntry
*back
= NULL
;
2052 real_id
= yelp_document_get_page_id (document
, priv
->page_id
);
2053 if (priv
->page_id
&& real_id
&& g_str_equal (real_id
, priv
->page_id
)) {
2058 g_free (priv
->page_id
);
2059 priv
->page_id
= real_id
;
2060 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2062 g_signal_emit_by_name (view
, "notify::page-id", spec
);
2065 g_free (priv
->root_title
);
2066 g_free (priv
->page_title
);
2067 g_free (priv
->page_desc
);
2068 g_free (priv
->page_icon
);
2070 priv
->root_title
= yelp_document_get_root_title (document
, priv
->page_id
);
2071 priv
->page_title
= yelp_document_get_page_title (document
, priv
->page_id
);
2072 priv
->page_desc
= yelp_document_get_page_desc (document
, priv
->page_id
);
2073 priv
->page_icon
= yelp_document_get_page_icon (document
, priv
->page_id
);
2076 back
= priv
->back_cur
->data
;
2078 g_free (back
->title
);
2079 back
->title
= g_strdup (priv
->page_title
);
2080 g_free (back
->desc
);
2081 back
->desc
= g_strdup (priv
->page_desc
);
2084 prev_id
= yelp_document_get_prev_id (document
, priv
->page_id
);
2085 action
= gtk_action_group_get_action (priv
->action_group
, "YelpViewGoPrevious");
2086 gtk_action_set_sensitive (action
, prev_id
!= NULL
);
2089 next_id
= yelp_document_get_next_id (document
, priv
->page_id
);
2090 action
= gtk_action_group_get_action (priv
->action_group
, "YelpViewGoNext");
2091 gtk_action_set_sensitive (action
, next_id
!= NULL
);
2094 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2096 g_signal_emit_by_name (view
, "notify::root-title", spec
);
2098 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2100 g_signal_emit_by_name (view
, "notify::page-title", spec
);
2102 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2104 g_signal_emit_by_name (view
, "notify::page-desc", spec
);
2106 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2108 g_signal_emit_by_name (view
, "notify::page-icon", spec
);
2110 else if (signal
== YELP_DOCUMENT_SIGNAL_CONTENTS
) {
2111 YelpUriDocumentType doctype
;
2112 const gchar
*contents
;
2113 gchar
*mime_type
, *page_id
, *frag_id
, *full_uri
;
2114 page_id
= yelp_uri_get_page_id (priv
->uri
);
2115 debug_print (DB_ARG
, " document.uri.page_id=\"%s\"\n", page_id
);
2116 mime_type
= yelp_document_get_mime_type (document
, page_id
);
2117 contents
= yelp_document_read_contents (document
, page_id
);
2118 frag_id
= yelp_uri_get_frag_id (priv
->uri
);
2119 g_free (priv
->bogus_uri
);
2120 /* We don't have actual page and frag IDs for DocBook. We just map IDs
2121 of block elements. The result is that we get xref:someid#someid.
2122 If someid is really the page ID, we just drop the frag reference.
2123 Otherwise, normal page views scroll past the link trail.
2125 if (frag_id
!= NULL
) {
2126 if (YELP_IS_DOCBOOK_DOCUMENT (document
)) {
2127 gchar
*real_id
= yelp_document_get_page_id (document
, page_id
);
2128 if (g_str_equal (real_id
, frag_id
)) {
2135 /* We have to give WebKit a URI in a scheme it understands, otherwise we
2136 won't get the resource-request-starting signal. So we can't use the
2137 canonical URI, because it might be something like ghelp. We also have
2138 to give it something unique, because WebKit ignores our load_string
2139 call if the URI isn't different. We could try to construct something
2140 based on actual file locations, but in fact it doesn't matter. So
2141 we just make a bogus URI that's easy to process later.
2143 doctype
= yelp_uri_get_document_type (priv
->uri
);
2144 full_uri
= yelp_uri_get_canonical_uri (priv
->uri
);
2145 if (g_str_has_prefix (full_uri
, "file:/") &&
2146 (doctype
== YELP_URI_DOCUMENT_TYPE_TEXT
||
2147 doctype
== YELP_URI_DOCUMENT_TYPE_HTML
||
2148 doctype
== YELP_URI_DOCUMENT_TYPE_XHTML
)) {
2149 priv
->bogus_uri
= full_uri
;
2153 if (frag_id
!= NULL
)
2154 priv
->bogus_uri
= g_strdup_printf ("%s%p#%s", BOGUS_URI
, priv
->uri
, frag_id
);
2156 priv
->bogus_uri
= g_strdup_printf ("%s%p", BOGUS_URI
, priv
->uri
);
2158 g_signal_handler_block (view
, priv
->navigation_requested
);
2159 webkit_web_view_load_string (WEBKIT_WEB_VIEW (view
),
2164 g_signal_handler_unblock (view
, priv
->navigation_requested
);
2165 g_object_set (view
, "state", YELP_VIEW_STATE_LOADED
, NULL
);
2167 /* If we need to set the GtkAdjustment or trigger the page title
2168 * from what WebKit thinks it is (see comment below), we need to
2169 * let the main loop run through.
2171 if (priv
->vadjust
> 0 || priv
->hadjust
> 0 || priv
->page_title
== NULL
)
2172 while (g_main_context_pending (NULL
)) {
2173 WebKitLoadStatus status
;
2174 status
= webkit_web_view_get_load_status (WEBKIT_WEB_VIEW (view
));
2175 g_main_context_iteration (NULL
, FALSE
);
2176 /* Sometimes some runaway JavaScript causes there to always
2177 * be pending sources. Break out if the document is loaded.
2179 if (status
== WEBKIT_LOAD_FINISHED
||
2180 status
== WEBKIT_LOAD_FAILED
)
2184 /* Setting adjustments only work after the page is loaded. These
2185 * are set by view_history_action, and they're reset to 0 after
2188 if (priv
->vadjust
> 0) {
2189 if (priv
->vadjustment
)
2190 gtk_adjustment_set_value (priv
->vadjustment
, priv
->vadjust
);
2193 if (priv
->hadjust
> 0) {
2194 if (priv
->hadjustment
)
2195 gtk_adjustment_set_value (priv
->hadjustment
, priv
->hadjust
);
2199 /* If the document didn't give us a page title, get it from WebKit.
2200 * We let the main loop run through so that WebKit gets the title
2201 * set so that we can send notify::page-title before loaded. It
2202 * simplifies things if YelpView consumers can assume the title
2203 * is set before loaded is triggered.
2205 if (priv
->page_title
== NULL
) {
2207 priv
->page_title
= g_strdup (webkit_web_view_get_title (WEBKIT_WEB_VIEW (view
)));
2208 spec
= g_object_class_find_property ((GObjectClass
*) YELP_VIEW_GET_CLASS (view
),
2210 g_signal_emit_by_name (view
, "notify::page-title", spec
);
2216 yelp_document_finish_read (document
, contents
);
2217 g_signal_emit (view
, signals
[LOADED
], 0);
2219 else if (signal
== YELP_DOCUMENT_SIGNAL_ERROR
) {
2220 view_show_error_page (view
, error
);