4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
20 #include <glib/gi18n-lib.h>
26 #include <pango/pango.h>
28 #include <camel/camel.h>
29 #include <libebackend/libebackend.h>
31 #include <libsoup/soup.h>
33 #include "e-alert-dialog.h"
34 #include "e-alert-sink.h"
35 #include "e-file-request.h"
36 #include "e-misc-utils.h"
37 #include "e-plugin-ui.h"
38 #include "e-popup-action.h"
39 #include "e-selectable.h"
40 #include "e-stock-request.h"
42 #include "web-extensions/e-web-extension-names.h"
44 #include "e-web-view.h"
46 #define E_WEB_VIEW_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE \
48 ((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
50 typedef struct _AsyncContext AsyncContext
;
52 typedef struct _ElementClickedData
{
53 EWebViewElementClickedFunc callback
;
57 struct _EWebViewPrivate
{
58 GtkUIManager
*ui_manager
;
60 gchar
*cursor_image_src
;
64 GtkAction
*open_proxy
;
65 GtkAction
*print_proxy
;
66 GtkAction
*save_as_proxy
;
68 /* Lockdown Options */
69 gboolean disable_printing
;
70 gboolean disable_save_to_disk
;
74 GSettings
*font_settings
;
75 gulong font_name_changed_handler_id
;
76 gulong monospace_font_name_changed_handler_id
;
78 GSettings
*aliasing_settings
;
79 gulong antialiasing_changed_handler_id
;
81 GHashTable
*old_settings
;
83 GDBusProxy
*web_extension
;
84 guint web_extension_watch_name_id
;
86 WebKitFindController
*find_controller
;
87 gulong found_text_handler_id
;
88 gulong failed_to_find_text_handler_id
;
90 gboolean has_hover_link
;
92 GSList
*content_requests
; /* EContentRequest * */
94 GHashTable
*element_clicked_cbs
; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
95 guint web_extension_element_clicked_signal_id
;
97 guint32 clipboard_flags
;
98 guint web_extension_clipboard_flags_changed_signal_id
;
101 guint web_extension_need_input_changed_signal_id
;
103 GCancellable
*load_cancellable
;
106 struct _AsyncContext
{
109 GInputStream
*input_stream
;
110 EContentRequest
*content_request
;
117 PROP_CLIPBOARD_FLAGS
,
118 PROP_COPY_TARGET_LIST
,
119 PROP_CURSOR_IMAGE_SRC
,
120 PROP_DISABLE_PRINTING
,
121 PROP_DISABLE_SAVE_TO_DISK
,
124 PROP_PASTE_TARGET_LIST
,
141 static guint signals
[LAST_SIGNAL
];
143 static const gchar
*ui
=
145 " <popup name='context'>"
146 " <menuitem action='copy-clipboard'/>"
148 " <placeholder name='custom-actions-1'>"
149 " <menuitem action='open'/>"
150 " <menuitem action='save-as'/>"
151 " <menuitem action='http-open'/>"
152 " <menuitem action='send-message'/>"
153 " <menuitem action='print'/>"
155 " <placeholder name='custom-actions-2'>"
156 " <menuitem action='uri-copy'/>"
157 " <menuitem action='mailto-copy'/>"
158 " <menuitem action='mailto-copy-raw'/>"
159 " <menuitem action='image-copy'/>"
160 " <menuitem action='image-save'/>"
162 " <placeholder name='custom-actions-3'/>"
164 " <menuitem action='select-all'/>"
165 " <placeholder name='inspect-menu' />"
169 /* Forward Declarations */
170 static void e_web_view_alert_sink_init (EAlertSinkInterface
*iface
);
171 static void e_web_view_selectable_init (ESelectableInterface
*iface
);
173 G_DEFINE_TYPE_WITH_CODE (
176 WEBKIT_TYPE_WEB_VIEW
,
177 G_IMPLEMENT_INTERFACE (
178 E_TYPE_EXTENSIBLE
, NULL
)
179 G_IMPLEMENT_INTERFACE (
181 e_web_view_alert_sink_init
)
182 G_IMPLEMENT_INTERFACE (
184 e_web_view_selectable_init
))
187 async_context_free (gpointer ptr
)
189 AsyncContext
*async_context
= ptr
;
194 g_clear_object (&async_context
->activity
);
195 g_clear_object (&async_context
->destination
);
196 g_clear_object (&async_context
->input_stream
);
197 g_clear_object (&async_context
->content_request
);
198 g_free (async_context
->uri
);
200 g_slice_free (AsyncContext
, async_context
);
204 action_copy_clipboard_cb (GtkAction
*action
,
207 e_web_view_copy_clipboard (web_view
);
211 action_http_open_cb (GtkAction
*action
,
217 parent
= gtk_widget_get_toplevel (GTK_WIDGET (web_view
));
218 parent
= gtk_widget_is_toplevel (parent
) ? parent
: NULL
;
220 uri
= e_web_view_get_selected_uri (web_view
);
221 g_return_if_fail (uri
!= NULL
);
223 e_show_uri (parent
, uri
);
227 webview_mailto_copy (EWebView
*web_view
,
228 gboolean only_email_address
)
231 CamelInternetAddress
*inet_addr
;
232 GtkClipboard
*clipboard
;
233 const gchar
*uri
, *name
= NULL
, *email
= NULL
;
236 uri
= e_web_view_get_selected_uri (web_view
);
237 g_return_if_fail (uri
!= NULL
);
239 /* This should work because we checked it in update_actions(). */
240 curl
= camel_url_new (uri
, NULL
);
241 g_return_if_fail (curl
!= NULL
);
243 inet_addr
= camel_internet_address_new ();
244 camel_address_decode (CAMEL_ADDRESS (inet_addr
), curl
->path
);
245 if (only_email_address
&&
246 camel_internet_address_get (inet_addr
, 0, &name
, &email
) &&
248 text
= g_strdup (email
);
250 text
= camel_address_format (CAMEL_ADDRESS (inet_addr
));
251 if (text
== NULL
|| *text
== '\0')
252 text
= g_strdup (uri
+ strlen ("mailto:"));
255 g_object_unref (inet_addr
);
256 camel_url_free (curl
);
258 clipboard
= gtk_clipboard_get (GDK_SELECTION_PRIMARY
);
259 gtk_clipboard_set_text (clipboard
, text
, -1);
260 gtk_clipboard_store (clipboard
);
262 clipboard
= gtk_clipboard_get (GDK_SELECTION_CLIPBOARD
);
263 gtk_clipboard_set_text (clipboard
, text
, -1);
264 gtk_clipboard_store (clipboard
);
270 action_mailto_copy_cb (GtkAction
*action
,
273 webview_mailto_copy (web_view
, FALSE
);
277 action_mailto_copy_raw_cb (GtkAction
*action
,
280 webview_mailto_copy (web_view
, TRUE
);
284 action_select_all_cb (GtkAction
*action
,
287 e_web_view_select_all (web_view
);
291 action_send_message_cb (GtkAction
*action
,
298 parent
= gtk_widget_get_toplevel (GTK_WIDGET (web_view
));
299 parent
= gtk_widget_is_toplevel (parent
) ? parent
: NULL
;
301 uri
= e_web_view_get_selected_uri (web_view
);
302 g_return_if_fail (uri
!= NULL
);
305 g_signal_emit (web_view
, signals
[PROCESS_MAILTO
], 0, uri
, &handled
);
308 e_show_uri (parent
, uri
);
312 action_uri_copy_cb (GtkAction
*action
,
315 GtkClipboard
*clipboard
;
318 uri
= e_web_view_get_selected_uri (web_view
);
319 g_return_if_fail (uri
!= NULL
);
321 clipboard
= gtk_clipboard_get (GDK_SELECTION_PRIMARY
);
322 gtk_clipboard_set_text (clipboard
, uri
, -1);
323 gtk_clipboard_store (clipboard
);
325 clipboard
= gtk_clipboard_get (GDK_SELECTION_CLIPBOARD
);
326 gtk_clipboard_set_text (clipboard
, uri
, -1);
327 gtk_clipboard_store (clipboard
);
331 action_image_copy_cb (GtkAction
*action
,
334 e_web_view_cursor_image_copy (web_view
);
338 action_image_save_cb (GtkAction
*action
,
341 e_web_view_cursor_image_save (web_view
);
344 static GtkActionEntry uri_entries
[] = {
348 N_("_Copy Link Location"),
350 N_("Copy the link to the clipboard"),
351 G_CALLBACK (action_uri_copy_cb
) }
354 static GtkActionEntry http_entries
[] = {
358 N_("_Open Link in Browser"),
360 N_("Open the link in a web browser"),
361 G_CALLBACK (action_http_open_cb
) }
364 static GtkActionEntry mailto_entries
[] = {
368 N_("_Copy Email Address"),
370 N_("Copy the email address to the clipboard"),
371 G_CALLBACK (action_mailto_copy_cb
) },
375 N_("Copy _Raw Email Address"),
377 N_("Copy the raw email address to the clipboard"),
378 G_CALLBACK (action_mailto_copy_raw_cb
) },
382 N_("_Send New Message To..."),
384 N_("Send a mail message to this address"),
385 G_CALLBACK (action_send_message_cb
) }
388 static GtkActionEntry image_entries
[] = {
394 N_("Copy the image to the clipboard"),
395 G_CALLBACK (action_image_copy_cb
) },
399 N_("Save _Image..."),
401 N_("Save the image to a file"),
402 G_CALLBACK (action_image_save_cb
) }
405 static GtkActionEntry selection_entries
[] = {
411 N_("Copy the selection"),
412 G_CALLBACK (action_copy_clipboard_cb
) },
415 static GtkActionEntry standard_entries
[] = {
421 N_("Select all text and images"),
422 G_CALLBACK (action_select_all_cb
) }
426 web_view_menu_item_select_cb (EWebView
*web_view
,
430 GtkActivatable
*activatable
;
431 const gchar
*tooltip
;
433 activatable
= GTK_ACTIVATABLE (widget
);
434 action
= gtk_activatable_get_related_action (activatable
);
435 tooltip
= gtk_action_get_tooltip (action
);
440 e_web_view_status_message (web_view
, tooltip
);
444 webkit_find_controller_found_text_cb (WebKitFindController
*find_controller
,
451 webkit_find_controller_failed_to_found_text_cb (WebKitFindController
*find_controller
,
457 web_view_set_find_controller (EWebView
*web_view
)
459 WebKitFindController
*find_controller
;
462 webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (web_view
));
464 web_view
->priv
->found_text_handler_id
= g_signal_connect (
465 find_controller
, "found-text",
466 G_CALLBACK (webkit_find_controller_found_text_cb
), web_view
);
468 web_view
->priv
->failed_to_find_text_handler_id
= g_signal_connect (
469 find_controller
, "failed-to-find-text",
470 G_CALLBACK (webkit_find_controller_failed_to_found_text_cb
), web_view
);
472 web_view
->priv
->find_controller
= find_controller
;
476 web_view_update_document_highlights (EWebView
*web_view
)
480 head
= g_queue_peek_head_link (&web_view
->priv
->highlights
);
482 for (link
= head
; link
!= NULL
; link
= g_list_next (link
)) {
483 webkit_find_controller_search (
484 web_view
->priv
->find_controller
,
486 WEBKIT_FIND_OPTIONS_NONE
,
492 web_view_menu_item_deselect_cb (EWebView
*web_view
)
494 e_web_view_status_message (web_view
, NULL
);
498 web_view_connect_proxy_cb (EWebView
*web_view
,
502 if (!GTK_IS_MENU_ITEM (proxy
))
505 g_signal_connect_swapped (
507 G_CALLBACK (web_view_menu_item_select_cb
), web_view
);
509 g_signal_connect_swapped (
511 G_CALLBACK (web_view_menu_item_deselect_cb
), web_view
);
515 web_view_context_menu_cb (WebKitWebView
*webkit_web_view
,
516 WebKitContextMenu
*context_menu
,
518 WebKitHitTestResult
*hit_test_result
,
521 WebKitHitTestResultContext context
;
523 gboolean event_handled
= FALSE
;
524 gchar
*link_uri
= NULL
;
526 web_view
= E_WEB_VIEW (webkit_web_view
);
528 g_free (web_view
->priv
->cursor_image_src
);
529 web_view
->priv
->cursor_image_src
= NULL
;
531 if (hit_test_result
== NULL
)
534 context
= webkit_hit_test_result_get_context (hit_test_result
);
536 if (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE
) {
537 gchar
*image_uri
= NULL
;
539 g_object_get (hit_test_result
, "image-uri", &image_uri
, NULL
);
541 if (image_uri
!= NULL
) {
542 g_free (web_view
->priv
->cursor_image_src
);
543 web_view
->priv
->cursor_image_src
= image_uri
;
547 if (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK
)
548 g_object_get (hit_test_result
, "link-uri", &link_uri
, NULL
);
552 signals
[POPUP_EVENT
], 0,
553 link_uri
, event
, &event_handled
);
557 return event_handled
;
561 web_view_mouse_target_changed_cb (EWebView
*web_view
,
562 WebKitHitTestResult
*hit_test_result
,
566 EWebViewClass
*class;
567 const gchar
*title
, *uri
;
569 title
= webkit_hit_test_result_get_link_title (hit_test_result
);
570 uri
= webkit_hit_test_result_get_link_uri (hit_test_result
);
572 web_view
->priv
->has_hover_link
= uri
&& *uri
;
574 /* XXX WebKitWebView does not provide a class method for
575 * this signal, so we do so we can override the default
576 * behavior from subclasses for special URI types. */
578 class = E_WEB_VIEW_GET_CLASS (web_view
);
579 g_return_if_fail (class->hovering_over_link
!= NULL
);
581 class->hovering_over_link (web_view
, title
, uri
);
585 web_view_decide_policy_cb (EWebView
*web_view
,
586 WebKitPolicyDecision
*decision
,
587 WebKitPolicyDecisionType type
)
589 EWebViewClass
*class;
590 WebKitNavigationPolicyDecision
*navigation_decision
;
591 WebKitNavigationAction
*navigation_action
;
592 WebKitNavigationType navigation_type
;
593 WebKitURIRequest
*request
;
594 const gchar
*uri
, *view_uri
;
596 if (type
!= WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION
&&
597 type
!= WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION
)
600 navigation_decision
= WEBKIT_NAVIGATION_POLICY_DECISION (decision
);
601 navigation_action
= webkit_navigation_policy_decision_get_navigation_action (navigation_decision
);
602 navigation_type
= webkit_navigation_action_get_navigation_type (navigation_action
);
604 if (navigation_type
!= WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
)
607 request
= webkit_navigation_action_get_request (navigation_action
);
608 uri
= webkit_uri_request_get_uri (request
);
609 view_uri
= webkit_web_view_get_uri (WEBKIT_WEB_VIEW (web_view
));
611 /* Allow navigation through fragments in page */
612 if (uri
&& *uri
&& view_uri
&& *view_uri
) {
613 SoupURI
*uri_link
, *uri_view
;
615 uri_link
= soup_uri_new (uri
);
616 uri_view
= soup_uri_new (view_uri
);
617 if (uri_link
&& uri_view
) {
618 const gchar
*tmp1
, *tmp2
;
620 tmp1
= soup_uri_get_scheme (uri_link
);
621 tmp2
= soup_uri_get_scheme (uri_view
);
623 /* The scheme on both URIs should be the same */
624 if (tmp1
&& tmp2
&& g_ascii_strcasecmp (tmp1
, tmp2
) != 0)
627 tmp1
= soup_uri_get_host (uri_link
);
628 tmp2
= soup_uri_get_host (uri_view
);
630 /* The host on both URIs should be the same */
631 if (tmp1
&& tmp2
&& g_ascii_strcasecmp (tmp1
, tmp2
) != 0)
634 /* URI from link should have fragment set - could be empty */
635 if (soup_uri_get_fragment (uri_link
)) {
636 soup_uri_free (uri_link
);
637 soup_uri_free (uri_view
);
638 webkit_policy_decision_use (decision
);
645 soup_uri_free (uri_link
);
647 soup_uri_free (uri_view
);
650 /* XXX WebKitWebView does not provide a class method for
651 * this signal, so we do so we can override the default
652 * behavior from subclasses for special URI types. */
654 class = E_WEB_VIEW_GET_CLASS (web_view
);
655 g_return_val_if_fail (class->link_clicked
!= NULL
, FALSE
);
657 webkit_policy_decision_ignore (decision
);
659 class->link_clicked (web_view
, uri
);
665 e_web_view_ensure_body_class (EWebView
*web_view
)
667 GDBusProxy
*web_extension
;
669 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
671 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
675 e_util_invoke_g_dbus_proxy_call_with_error_check (
677 "EWebViewEnsureBodyClass",
680 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
681 "-e-web-view-background-color -e-web-view-text-color"),
686 style_updated_cb (EWebView
*web_view
)
691 GtkStyleContext
*style_context
;
693 style_context
= gtk_widget_get_style_context (GTK_WIDGET (web_view
));
695 if (gtk_style_context_lookup_color (style_context
, "theme_base_color", &color
))
696 color_value
= g_strdup_printf ("#%06x", e_rgba_to_value (&color
));
698 color_value
= g_strdup (E_UTILS_DEFAULT_THEME_BASE_COLOR
);
699 if (!gdk_rgba_parse (&color
, color_value
)) {
707 style
= g_strconcat ("background-color: ", color_value
, ";", NULL
);
709 webkit_web_view_set_background_color (WEBKIT_WEB_VIEW (web_view
), &color
);
711 e_web_view_add_css_rule_into_style_sheet (
713 "-e-web-view-style-sheet",
714 ".-e-web-view-background-color",
717 g_free (color_value
);
720 if (gtk_style_context_lookup_color (style_context
, "theme_fg_color", &color
))
721 color_value
= g_strdup_printf ("#%06x", e_rgba_to_value (&color
));
723 color_value
= g_strdup (E_UTILS_DEFAULT_THEME_FG_COLOR
);
725 style
= g_strconcat ("color: ", color_value
, ";", NULL
);
727 e_web_view_add_css_rule_into_style_sheet (
729 "-e-web-view-style-sheet",
730 ".-e-web-view-text-color",
733 g_free (color_value
);
738 web_view_load_changed_cb (WebKitWebView
*webkit_web_view
,
739 WebKitLoadEvent load_event
,
744 web_view
= E_WEB_VIEW (webkit_web_view
);
746 if (load_event
== WEBKIT_LOAD_STARTED
)
747 g_hash_table_remove_all (web_view
->priv
->element_clicked_cbs
);
749 if (load_event
!= WEBKIT_LOAD_FINISHED
)
752 e_web_view_ensure_body_class (web_view
);
753 style_updated_cb (web_view
);
755 web_view_update_document_highlights (web_view
);
758 static GObjectConstructParam
*
759 find_property (guint n_properties
,
760 GObjectConstructParam
* properties
,
761 GParamSpec
* param_spec
)
763 while (n_properties
--) {
764 if (properties
->pspec
== param_spec
)
773 web_view_constructor (GType type
,
774 guint n_construct_properties
,
775 GObjectConstructParam
*construct_properties
)
777 GObjectClass
* object_class
;
778 GParamSpec
* param_spec
;
779 GObjectConstructParam
*param
= NULL
;
781 object_class
= G_OBJECT_CLASS (g_type_class_ref(type
));
782 g_return_val_if_fail (object_class
!= NULL
, NULL
);
784 if (construct_properties
&& n_construct_properties
!= 0) {
785 param_spec
= g_object_class_find_property (object_class
, "settings");
786 if ((param
= find_property (n_construct_properties
, construct_properties
, param_spec
)))
787 g_value_take_object (param
->value
, e_web_view_get_default_webkit_settings ());
788 param_spec
= g_object_class_find_property(object_class
, "user-content-manager");
789 if ((param
= find_property (n_construct_properties
, construct_properties
, param_spec
)))
790 g_value_take_object (param
->value
, webkit_user_content_manager_new ());
793 g_type_class_unref (object_class
);
795 return G_OBJECT_CLASS (e_web_view_parent_class
)->constructor(type
, n_construct_properties
, construct_properties
);
799 web_view_set_property (GObject
*object
,
804 switch (property_id
) {
805 case PROP_CARET_MODE
:
806 e_web_view_set_caret_mode (
808 g_value_get_boolean (value
));
811 case PROP_CLIPBOARD_FLAGS
:
812 e_web_view_set_clipboard_flags (
814 g_value_get_uint (value
));
817 case PROP_COPY_TARGET_LIST
:
818 /* This is a fake property. */
819 g_warning ("%s: EWebView::copy-target-list not used", G_STRFUNC
);
822 case PROP_CURSOR_IMAGE_SRC
:
823 e_web_view_set_cursor_image_src (
825 g_value_get_string (value
));
828 case PROP_DISABLE_PRINTING
:
829 e_web_view_set_disable_printing (
831 g_value_get_boolean (value
));
834 case PROP_DISABLE_SAVE_TO_DISK
:
835 e_web_view_set_disable_save_to_disk (
837 g_value_get_boolean (value
));
840 case PROP_NEED_INPUT
:
841 e_web_view_set_need_input (
843 g_value_get_boolean (value
));
846 case PROP_OPEN_PROXY
:
847 e_web_view_set_open_proxy (
849 g_value_get_object (value
));
852 case PROP_PASTE_TARGET_LIST
:
853 /* This is a fake property. */
854 g_warning ("%s: EWebView::paste-target-list not used", G_STRFUNC
);
857 case PROP_PRINT_PROXY
:
858 e_web_view_set_print_proxy (
860 g_value_get_object (value
));
863 case PROP_SAVE_AS_PROXY
:
864 e_web_view_set_save_as_proxy (
866 g_value_get_object (value
));
869 case PROP_SELECTED_URI
:
870 e_web_view_set_selected_uri (
872 g_value_get_string (value
));
875 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
879 web_view_get_property (GObject
*object
,
884 switch (property_id
) {
885 case PROP_CARET_MODE
:
886 g_value_set_boolean (
887 value
, e_web_view_get_caret_mode (
888 E_WEB_VIEW (object
)));
891 case PROP_CLIPBOARD_FLAGS
:
893 value
, e_web_view_get_clipboard_flags (
894 E_WEB_VIEW (object
)));
897 case PROP_COPY_TARGET_LIST
:
898 /* This is a fake property. */
899 g_value_set_boxed (value
, NULL
);
902 case PROP_CURSOR_IMAGE_SRC
:
904 value
, e_web_view_get_cursor_image_src (
905 E_WEB_VIEW (object
)));
908 case PROP_DISABLE_PRINTING
:
909 g_value_set_boolean (
910 value
, e_web_view_get_disable_printing (
911 E_WEB_VIEW (object
)));
914 case PROP_DISABLE_SAVE_TO_DISK
:
915 g_value_set_boolean (
916 value
, e_web_view_get_disable_save_to_disk (
917 E_WEB_VIEW (object
)));
920 case PROP_NEED_INPUT
:
921 g_value_set_boolean (
922 value
, e_web_view_get_need_input (
923 E_WEB_VIEW (object
)));
926 case PROP_OPEN_PROXY
:
928 value
, e_web_view_get_open_proxy (
929 E_WEB_VIEW (object
)));
932 case PROP_PASTE_TARGET_LIST
:
933 /* This is a fake property. */
934 g_value_set_boxed (value
, NULL
);
937 case PROP_PRINT_PROXY
:
939 value
, e_web_view_get_print_proxy (
940 E_WEB_VIEW (object
)));
943 case PROP_SAVE_AS_PROXY
:
945 value
, e_web_view_get_save_as_proxy (
946 E_WEB_VIEW (object
)));
949 case PROP_SELECTED_URI
:
951 value
, e_web_view_get_selected_uri (
952 E_WEB_VIEW (object
)));
957 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
961 web_view_dispose (GObject
*object
)
963 EWebViewPrivate
*priv
;
965 priv
= E_WEB_VIEW_GET_PRIVATE (object
);
967 if (priv
->load_cancellable
) {
968 g_cancellable_cancel (priv
->load_cancellable
);
969 g_clear_object (&priv
->load_cancellable
);
972 if (priv
->font_name_changed_handler_id
> 0) {
973 g_signal_handler_disconnect (
975 priv
->font_name_changed_handler_id
);
976 priv
->font_name_changed_handler_id
= 0;
979 if (priv
->monospace_font_name_changed_handler_id
> 0) {
980 g_signal_handler_disconnect (
982 priv
->monospace_font_name_changed_handler_id
);
983 priv
->monospace_font_name_changed_handler_id
= 0;
986 if (priv
->antialiasing_changed_handler_id
> 0) {
987 g_signal_handler_disconnect (
988 priv
->aliasing_settings
,
989 priv
->antialiasing_changed_handler_id
);
990 priv
->antialiasing_changed_handler_id
= 0;
993 if (priv
->web_extension_watch_name_id
> 0) {
994 g_bus_unwatch_name (priv
->web_extension_watch_name_id
);
995 priv
->web_extension_watch_name_id
= 0;
998 if (priv
->found_text_handler_id
> 0) {
999 g_signal_handler_disconnect (
1000 priv
->find_controller
,
1001 priv
->found_text_handler_id
);
1002 priv
->found_text_handler_id
= 0;
1005 if (priv
->failed_to_find_text_handler_id
> 0) {
1006 g_signal_handler_disconnect (
1007 priv
->find_controller
,
1008 priv
->failed_to_find_text_handler_id
);
1009 priv
->failed_to_find_text_handler_id
= 0;
1012 if (priv
->web_extension
&& priv
->web_extension_clipboard_flags_changed_signal_id
) {
1013 g_dbus_connection_signal_unsubscribe (
1014 g_dbus_proxy_get_connection (priv
->web_extension
),
1015 priv
->web_extension_clipboard_flags_changed_signal_id
);
1016 priv
->web_extension_clipboard_flags_changed_signal_id
= 0;
1019 if (priv
->web_extension
&& priv
->web_extension_need_input_changed_signal_id
) {
1020 g_dbus_connection_signal_unsubscribe (
1021 g_dbus_proxy_get_connection (priv
->web_extension
),
1022 priv
->web_extension_need_input_changed_signal_id
);
1023 priv
->web_extension_need_input_changed_signal_id
= 0;
1026 if (priv
->web_extension
&& priv
->web_extension_element_clicked_signal_id
) {
1027 g_dbus_connection_signal_unsubscribe (
1028 g_dbus_proxy_get_connection (priv
->web_extension
),
1029 priv
->web_extension_element_clicked_signal_id
);
1030 priv
->web_extension_element_clicked_signal_id
= 0;
1033 g_hash_table_remove_all (priv
->element_clicked_cbs
);
1035 g_slist_free_full (priv
->content_requests
, g_object_unref
);
1036 priv
->content_requests
= NULL
;
1038 g_clear_object (&priv
->ui_manager
);
1039 g_clear_object (&priv
->open_proxy
);
1040 g_clear_object (&priv
->print_proxy
);
1041 g_clear_object (&priv
->save_as_proxy
);
1042 g_clear_object (&priv
->aliasing_settings
);
1043 g_clear_object (&priv
->font_settings
);
1044 g_clear_object (&priv
->web_extension
);
1046 /* Chain up to parent's dispose() method. */
1047 G_OBJECT_CLASS (e_web_view_parent_class
)->dispose (object
);
1051 web_view_finalize (GObject
*object
)
1053 EWebViewPrivate
*priv
;
1055 priv
= E_WEB_VIEW_GET_PRIVATE (object
);
1057 g_free (priv
->selected_uri
);
1058 g_free (priv
->cursor_image_src
);
1060 while (!g_queue_is_empty (&priv
->highlights
))
1061 g_free (g_queue_pop_head (&priv
->highlights
));
1063 if (priv
->old_settings
) {
1064 g_hash_table_destroy (priv
->old_settings
);
1065 priv
->old_settings
= NULL
;
1068 g_hash_table_destroy (priv
->element_clicked_cbs
);
1070 /* Chain up to parent's finalize() method. */
1071 G_OBJECT_CLASS (e_web_view_parent_class
)->finalize (object
);
1076 web_view_uri_request_done_cb (GObject
*source_object
,
1077 GAsyncResult
*result
,
1080 WebKitURISchemeRequest
*request
= user_data
;
1081 GInputStream
*stream
= NULL
;
1082 gint64 stream_length
= -1;
1083 gchar
*mime_type
= NULL
;
1084 GError
*error
= NULL
;
1086 g_return_if_fail (E_IS_CONTENT_REQUEST (source_object
));
1087 g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request
));
1089 if (!e_content_request_process_finish (E_CONTENT_REQUEST (source_object
),
1090 result
, &stream
, &stream_length
, &mime_type
, &error
)) {
1091 webkit_uri_scheme_request_finish_error (request
, error
);
1092 g_clear_error (&error
);
1094 webkit_uri_scheme_request_finish (request
, stream
, stream_length
, mime_type
);
1096 g_clear_object (&stream
);
1100 g_object_unref (request
);
1104 web_view_process_uri_request_cb (WebKitURISchemeRequest
*request
,
1107 EWebView
*web_view
= NULL
;
1108 EContentRequest
*content_request
= user_data
;
1110 gchar
*redirect_to_uri
= NULL
;
1113 g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request
));
1114 g_return_if_fail (E_IS_CONTENT_REQUEST (content_request
));
1116 uri
= webkit_uri_scheme_request_get_uri (request
);
1117 requester
= G_OBJECT (webkit_uri_scheme_request_get_web_view (request
));
1122 error
= g_error_new_literal (G_IO_ERROR
, G_IO_ERROR_CANCELLED
, "Cancelled");
1123 webkit_uri_scheme_request_finish_error (request
, error
);
1124 g_clear_error (&error
);
1129 g_return_if_fail (e_content_request_can_process_uri (content_request
, uri
));
1131 if (E_IS_WEB_VIEW (requester
)) {
1132 /* Expects an empty string to abandon the request,
1133 or NULL to keep the passed-in uri,
1134 or a new uri to load instead. */
1135 g_signal_emit (requester
, signals
[URI_REQUESTED
], 0, uri
, &redirect_to_uri
);
1137 if (redirect_to_uri
&& *redirect_to_uri
) {
1138 uri
= redirect_to_uri
;
1139 } else if (redirect_to_uri
) {
1142 g_free (redirect_to_uri
);
1144 error
= g_error_new_literal (G_IO_ERROR
, G_IO_ERROR_CANCELLED
, "Cancelled");
1146 webkit_uri_scheme_request_finish_error (request
, error
);
1147 g_clear_error (&error
);
1152 web_view
= E_WEB_VIEW (requester
);
1155 e_content_request_process (content_request
, uri
, requester
, web_view
? web_view
->priv
->load_cancellable
: NULL
,
1156 web_view_uri_request_done_cb
, g_object_ref (request
));
1158 g_free (redirect_to_uri
);
1161 /* 'scheme' is like "file", not "file:" */
1163 e_web_view_register_content_request_for_scheme (EWebView
*web_view
,
1164 const gchar
*scheme
,
1165 EContentRequest
*content_request
)
1167 WebKitWebContext
*web_context
;
1169 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1170 g_return_if_fail (E_IS_CONTENT_REQUEST (content_request
));
1171 g_return_if_fail (scheme
!= NULL
);
1173 web_context
= webkit_web_view_get_context (WEBKIT_WEB_VIEW (web_view
));
1175 webkit_web_context_register_uri_scheme (web_context
, scheme
, web_view_process_uri_request_cb
,
1176 g_object_ref (content_request
), g_object_unref
);
1178 if (!g_slist_find (web_view
->priv
->content_requests
, content_request
)) {
1179 web_view
->priv
->content_requests
= g_slist_prepend (
1180 web_view
->priv
->content_requests
,
1181 g_object_ref (content_request
));
1186 web_view_initialize (WebKitWebView
*web_view
)
1188 WebKitWebContext
*web_context
;
1189 EContentRequest
*content_request
;
1190 const gchar
*id
= "org.gnome.settings-daemon.plugins.xsettings";
1191 GSettings
*settings
= NULL
, *font_settings
;
1192 GSettingsSchema
*settings_schema
;
1194 web_context
= webkit_web_view_get_context (web_view
);
1196 webkit_web_context_set_cache_model (web_context
, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER
);
1198 content_request
= e_file_request_new ();
1199 e_web_view_register_content_request_for_scheme (E_WEB_VIEW (web_view
), "evo-file", content_request
);
1200 g_object_unref (content_request
);
1202 content_request
= e_stock_request_new ();
1203 e_web_view_register_content_request_for_scheme (E_WEB_VIEW (web_view
), "gtk-stock", content_request
);
1204 g_object_unref (content_request
);
1206 /* Optional schema */
1207 settings_schema
= g_settings_schema_source_lookup (
1208 g_settings_schema_source_get_default (), id
, FALSE
);
1210 if (settings_schema
)
1211 settings
= e_util_ref_settings (id
);
1213 font_settings
= e_util_ref_settings ("org.gnome.desktop.interface");
1214 e_web_view_update_fonts_settings (
1215 font_settings
, settings
, NULL
, NULL
, GTK_WIDGET (web_view
));
1217 g_object_unref (font_settings
);
1219 g_object_unref (settings
);
1224 web_view_constructed (GObject
*object
)
1226 WebKitSettings
*web_settings
;
1228 GSettings
*settings
;
1230 settings
= e_util_ref_settings ("org.gnome.desktop.lockdown");
1233 settings
, "disable-printing",
1234 object
, "disable-printing",
1235 G_SETTINGS_BIND_GET
);
1238 settings
, "disable-save-to-disk",
1239 object
, "disable-save-to-disk",
1240 G_SETTINGS_BIND_GET
);
1242 g_object_unref (settings
);
1245 e_extensible_load_extensions (E_EXTENSIBLE (object
));
1247 /* Chain up to parent's constructed() method. */
1248 G_OBJECT_CLASS (e_web_view_parent_class
)->constructed (object
);
1250 web_settings
= webkit_web_view_get_settings (WEBKIT_WEB_VIEW (object
));
1253 G_OBJECT (web_settings
),
1254 "default-charset", "UTF-8",
1257 e_binding_bind_property (
1258 web_settings
, "enable-caret-browsing",
1259 E_WEB_VIEW (object
), "caret-mode",
1260 G_BINDING_BIDIRECTIONAL
|
1261 G_BINDING_SYNC_CREATE
);
1263 web_view_initialize (WEBKIT_WEB_VIEW (object
));
1265 web_view_set_find_controller (E_WEB_VIEW (object
));
1269 e_web_view_replace_load_cancellable (EWebView
*web_view
,
1270 gboolean create_new
)
1272 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1274 if (web_view
->priv
->load_cancellable
) {
1275 g_cancellable_cancel (web_view
->priv
->load_cancellable
);
1276 g_clear_object (&web_view
->priv
->load_cancellable
);
1280 web_view
->priv
->load_cancellable
= g_cancellable_new ();
1284 web_view_scroll_event (GtkWidget
*widget
,
1285 GdkEventScroll
*event
)
1287 if (event
->state
& GDK_CONTROL_MASK
) {
1288 GdkScrollDirection direction
= event
->direction
;
1290 if (direction
== GDK_SCROLL_SMOOTH
) {
1291 static gdouble total_delta_y
= 0.0;
1293 total_delta_y
+= event
->delta_y
;
1295 if (total_delta_y
>= 1.0) {
1296 total_delta_y
= 0.0;
1297 direction
= GDK_SCROLL_DOWN
;
1298 } else if (total_delta_y
<= -1.0) {
1299 total_delta_y
= 0.0;
1300 direction
= GDK_SCROLL_UP
;
1301 } else if (event
->delta_y
>= 1e-9 || event
->delta_y
<= -1e-9) {
1308 switch (direction
) {
1310 e_web_view_zoom_in (E_WEB_VIEW (widget
));
1312 case GDK_SCROLL_DOWN
:
1313 e_web_view_zoom_out (E_WEB_VIEW (widget
));
1320 return GTK_WIDGET_CLASS (e_web_view_parent_class
)->
1321 scroll_event (widget
, event
);
1325 web_view_drag_motion (GtkWidget
*widget
,
1326 GdkDragContext
*context
,
1331 /* Made this way to not pretend that this is a drop zone,
1332 when only FALSE had been returned, even it is supposed
1333 to be enough. Remove web_view_drag_leave() once fixed. */
1334 gdk_drag_status (context
, 0, time_
);
1340 web_view_drag_drop (GtkWidget
*widget
,
1341 GdkDragContext
*context
,
1346 /* Defined to avoid crash in WebKit */
1351 web_view_drag_leave (GtkWidget
*widget
,
1352 GdkDragContext
*context
,
1355 /* Defined to avoid crash in WebKit, when the web_view_drag_motion()
1356 uses the other way around. */
1360 web_view_hovering_over_link (EWebView
*web_view
,
1364 CamelInternetAddress
*address
;
1366 const gchar
*format
= NULL
;
1367 gchar
*message
= NULL
;
1370 if (uri
== NULL
|| *uri
== '\0')
1373 if (g_str_has_prefix (uri
, "mailto:"))
1374 format
= _("Click to mail %s");
1375 else if (g_str_has_prefix (uri
, "callto:") ||
1376 g_str_has_prefix (uri
, "h323:") ||
1377 g_str_has_prefix (uri
, "sip:") ||
1378 g_str_has_prefix (uri
, "tel:"))
1379 format
= _("Click to call %s");
1380 else if (g_str_has_prefix (uri
, "##"))
1381 message
= g_strdup (_("Click to hide/unhide addresses"));
1382 else if (g_str_has_prefix (uri
, "mail:")) {
1383 const gchar
*fragment
;
1386 soup_uri
= soup_uri_new (uri
);
1390 fragment
= soup_uri_get_fragment (soup_uri
);
1391 if (fragment
&& *fragment
)
1392 message
= g_strdup_printf (_("Go to the section %s of the message"), fragment
);
1394 message
= g_strdup (_("Go to the beginning of the message"));
1396 soup_uri_free (soup_uri
);
1398 message
= g_strdup_printf (_("Click to open %s"), uri
);
1403 /* XXX Use something other than Camel here. Surely
1404 * there's other APIs around that can do this. */
1405 curl
= camel_url_new (uri
, NULL
);
1406 address
= camel_internet_address_new ();
1407 camel_address_decode (CAMEL_ADDRESS (address
), curl
->path
);
1408 who
= camel_address_format (CAMEL_ADDRESS (address
));
1409 g_object_unref (address
);
1410 camel_url_free (curl
);
1413 who
= g_strdup (strchr (uri
, ':') + 1);
1415 message
= g_strdup_printf (format
, who
);
1420 e_web_view_status_message (web_view
, message
);
1426 web_view_link_clicked (EWebView
*web_view
,
1431 if (uri
&& g_ascii_strncasecmp (uri
, "mailto:", 7) == 0) {
1432 gboolean handled
= FALSE
;
1435 web_view
, signals
[PROCESS_MAILTO
], 0, uri
, &handled
);
1441 parent
= gtk_widget_get_toplevel (GTK_WIDGET (web_view
));
1442 parent
= gtk_widget_is_toplevel (parent
) ? parent
: NULL
;
1444 e_show_uri (parent
, uri
);
1448 web_view_load_string (EWebView
*web_view
,
1449 const gchar
*string
)
1454 webkit_web_view_load_html (
1455 WEBKIT_WEB_VIEW (web_view
), string
, "evo-file:///");
1459 web_view_load_uri (EWebView
*web_view
,
1463 uri
= "about:blank";
1465 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view
), uri
);
1469 web_view_suggest_filename (EWebView
*web_view
,
1474 /* Try to derive a filename from the last path segment. */
1476 cp
= strrchr (uri
, '/');
1478 if (strchr (cp
, '?') == NULL
)
1484 return g_strdup (cp
);
1488 web_view_popup_event (EWebView
*web_view
,
1492 e_web_view_set_selected_uri (web_view
, uri
);
1493 e_web_view_show_popup_menu (web_view
, event
);
1499 web_view_stop_loading (EWebView
*web_view
)
1501 e_web_view_replace_load_cancellable (web_view
, FALSE
);
1502 webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view
));
1506 web_view_register_element_clicked_hfunc (gpointer key
,
1510 const gchar
*elem_class
= key
;
1511 EWebView
*web_view
= user_data
;
1513 g_return_if_fail (elem_class
&& *elem_class
);
1514 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1516 if (!web_view
->priv
->web_extension
)
1519 e_util_invoke_g_dbus_proxy_call_with_error_check (
1520 web_view
->priv
->web_extension
,
1521 "RegisterElementClicked",
1524 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
1530 web_view_need_input_changed_signal_cb (GDBusConnection
*connection
,
1531 const gchar
*sender_name
,
1532 const gchar
*object_path
,
1533 const gchar
*interface_name
,
1534 const gchar
*signal_name
,
1535 GVariant
*parameters
,
1538 EWebView
*web_view
= user_data
;
1539 guint64 page_id
= 0;
1540 gboolean need_input
= FALSE
;
1542 if (g_strcmp0 (signal_name
, "NeedInputChanged") != 0)
1545 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1550 g_variant_get (parameters
, "(tb)", &page_id
, &need_input
);
1552 if (page_id
== webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)))
1553 e_web_view_set_need_input (web_view
, need_input
);
1557 web_view_clipboard_flags_changed_signal_cb (GDBusConnection
*connection
,
1558 const gchar
*sender_name
,
1559 const gchar
*object_path
,
1560 const gchar
*interface_name
,
1561 const gchar
*signal_name
,
1562 GVariant
*parameters
,
1565 EWebView
*web_view
= user_data
;
1566 guint64 page_id
= 0;
1567 guint32 clipboard_flags
= 0;
1569 if (g_strcmp0 (signal_name
, "ClipboardFlagsChanged") != 0)
1572 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1577 g_variant_get (parameters
, "(tu)", &page_id
, &clipboard_flags
);
1579 if (page_id
== webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)))
1580 e_web_view_set_clipboard_flags (web_view
, clipboard_flags
);
1584 web_view_element_clicked_signal_cb (GDBusConnection
*connection
,
1585 const gchar
*sender_name
,
1586 const gchar
*object_path
,
1587 const gchar
*interface_name
,
1588 const gchar
*signal_name
,
1589 GVariant
*parameters
,
1592 EWebView
*web_view
= user_data
;
1593 const gchar
*elem_class
= NULL
, *elem_value
= NULL
;
1594 GtkAllocation elem_position
;
1595 guint64 page_id
= 0;
1596 gint position_left
= 0, position_top
= 0, position_width
= 0, position_height
= 0;
1597 GPtrArray
*listeners
;
1599 if (g_strcmp0 (signal_name
, "ElementClicked") != 0)
1602 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1607 g_variant_get (parameters
, "(t&s&siiii)", &page_id
, &elem_class
, &elem_value
, &position_left
, &position_top
, &position_width
, &position_height
);
1609 if (!elem_class
|| !*elem_class
|| page_id
!= webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)))
1612 elem_position
.x
= position_left
;
1613 elem_position
.y
= position_top
;
1614 elem_position
.width
= position_width
;
1615 elem_position
.height
= position_height
;
1617 listeners
= g_hash_table_lookup (web_view
->priv
->element_clicked_cbs
, elem_class
);
1621 for (ii
= 0; ii
<listeners
->len
; ii
++) {
1622 ElementClickedData
*ecd
= g_ptr_array_index (listeners
, ii
);
1624 if (ecd
&& ecd
->callback
)
1625 ecd
->callback (web_view
, elem_class
, elem_value
, &elem_position
, ecd
->user_data
);
1631 web_extension_proxy_created_cb (GDBusProxy
*proxy
,
1632 GAsyncResult
*result
,
1633 GWeakRef
*web_view_ref
)
1636 GError
*error
= NULL
;
1638 g_return_if_fail (web_view_ref
!= NULL
);
1640 web_view
= g_weak_ref_get (web_view_ref
);
1643 e_weak_ref_free (web_view_ref
);
1647 web_view
->priv
->web_extension
= g_dbus_proxy_new_finish (result
, &error
);
1648 if (!web_view
->priv
->web_extension
) {
1649 g_warning ("Error creating web extension proxy: %s\n", error
->message
);
1650 g_error_free (error
);
1652 web_view
->priv
->web_extension_clipboard_flags_changed_signal_id
=
1653 g_dbus_connection_signal_subscribe (
1654 g_dbus_proxy_get_connection (web_view
->priv
->web_extension
),
1655 g_dbus_proxy_get_name (web_view
->priv
->web_extension
),
1656 E_WEB_EXTENSION_INTERFACE
,
1657 "ClipboardFlagsChanged",
1658 E_WEB_EXTENSION_OBJECT_PATH
,
1660 G_DBUS_SIGNAL_FLAGS_NONE
,
1661 web_view_clipboard_flags_changed_signal_cb
,
1665 web_view
->priv
->web_extension_need_input_changed_signal_id
=
1666 g_dbus_connection_signal_subscribe (
1667 g_dbus_proxy_get_connection (web_view
->priv
->web_extension
),
1668 g_dbus_proxy_get_name (web_view
->priv
->web_extension
),
1669 E_WEB_EXTENSION_INTERFACE
,
1671 E_WEB_EXTENSION_OBJECT_PATH
,
1673 G_DBUS_SIGNAL_FLAGS_NONE
,
1674 web_view_need_input_changed_signal_cb
,
1678 web_view
->priv
->web_extension_element_clicked_signal_id
=
1679 g_dbus_connection_signal_subscribe (
1680 g_dbus_proxy_get_connection (web_view
->priv
->web_extension
),
1681 g_dbus_proxy_get_name (web_view
->priv
->web_extension
),
1682 E_WEB_EXTENSION_INTERFACE
,
1684 E_WEB_EXTENSION_OBJECT_PATH
,
1686 G_DBUS_SIGNAL_FLAGS_NONE
,
1687 web_view_element_clicked_signal_cb
,
1691 g_hash_table_foreach (web_view
->priv
->element_clicked_cbs
, web_view_register_element_clicked_hfunc
, web_view
);
1693 e_web_view_ensure_body_class (web_view
);
1694 style_updated_cb (web_view
);
1697 g_clear_object (&web_view
);
1698 e_weak_ref_free (web_view_ref
);
1702 web_extension_appeared_cb (GDBusConnection
*connection
,
1704 const gchar
*name_owner
,
1705 GWeakRef
*web_view_ref
)
1709 g_return_if_fail (web_view_ref
!= NULL
);
1711 web_view
= g_weak_ref_get (web_view_ref
);
1718 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
|
1719 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
,
1722 E_WEB_EXTENSION_OBJECT_PATH
,
1723 E_WEB_EXTENSION_INTERFACE
,
1725 (GAsyncReadyCallback
) web_extension_proxy_created_cb
,
1726 e_weak_ref_new (web_view
));
1728 g_clear_object (&web_view
);
1732 web_extension_vanished_cb (GDBusConnection
*connection
,
1734 GWeakRef
*web_view_ref
)
1738 g_return_if_fail (web_view_ref
!= NULL
);
1740 web_view
= g_weak_ref_get (web_view_ref
);
1745 g_clear_object (&web_view
->priv
->web_extension
);
1746 g_clear_object (&web_view
);
1750 web_view_watch_web_extension (EWebView
*web_view
)
1752 web_view
->priv
->web_extension_watch_name_id
=
1755 E_WEB_EXTENSION_SERVICE_NAME
,
1756 G_BUS_NAME_WATCHER_FLAGS_NONE
,
1757 (GBusNameAppearedCallback
) web_extension_appeared_cb
,
1758 (GBusNameVanishedCallback
) web_extension_vanished_cb
,
1759 e_weak_ref_new (web_view
),
1760 (GDestroyNotify
) e_weak_ref_free
);
1764 e_web_view_get_web_extension_proxy (EWebView
*web_view
)
1766 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
1768 return web_view
->priv
->web_extension
;
1772 web_view_update_actions (EWebView
*web_view
)
1774 GtkActionGroup
*action_group
;
1776 gboolean scheme_is_http
= FALSE
;
1777 gboolean scheme_is_mailto
= FALSE
;
1778 gboolean uri_is_valid
= FALSE
;
1780 const gchar
*cursor_image_src
;
1781 const gchar
*group_name
;
1784 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
1786 uri
= e_web_view_get_selected_uri (web_view
);
1787 can_copy
= (e_web_view_get_clipboard_flags (web_view
) & E_CLIPBOARD_CAN_COPY
) != 0;
1788 cursor_image_src
= e_web_view_get_cursor_image_src (web_view
);
1790 /* Parse the URI early so we know if the actions will work. */
1794 curl
= camel_url_new (uri
, NULL
);
1795 uri_is_valid
= (curl
!= NULL
);
1796 camel_url_free (curl
);
1799 (g_ascii_strncasecmp (uri
, "http:", 5) == 0) ||
1800 (g_ascii_strncasecmp (uri
, "https:", 6) == 0);
1803 (g_ascii_strncasecmp (uri
, "mailto:", 7) == 0);
1806 /* Allow copying the URI even if it's malformed. */
1808 visible
= (uri
!= NULL
) && !scheme_is_mailto
;
1809 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1810 gtk_action_group_set_visible (action_group
, visible
);
1812 group_name
= "http";
1813 visible
= uri_is_valid
&& scheme_is_http
;
1814 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1815 gtk_action_group_set_visible (action_group
, visible
);
1817 group_name
= "mailto";
1818 visible
= uri_is_valid
&& scheme_is_mailto
;
1819 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1820 gtk_action_group_set_visible (action_group
, visible
);
1825 curl
= camel_url_new (uri
, NULL
);
1827 CamelInternetAddress
*inet_addr
;
1828 const gchar
*name
= NULL
, *email
= NULL
;
1831 inet_addr
= camel_internet_address_new ();
1832 camel_address_decode (CAMEL_ADDRESS (inet_addr
), curl
->path
);
1834 action
= gtk_action_group_get_action (action_group
, "mailto-copy-raw");
1835 gtk_action_set_visible (action
,
1836 camel_internet_address_get (inet_addr
, 0, &name
, &email
) &&
1837 name
&& *name
&& email
&& *email
);
1839 g_object_unref (inet_addr
);
1840 camel_url_free (curl
);
1844 group_name
= "image";
1845 visible
= (cursor_image_src
!= NULL
);
1846 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1847 gtk_action_group_set_visible (action_group
, visible
);
1849 group_name
= "selection";
1851 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1852 gtk_action_group_set_visible (action_group
, visible
);
1854 group_name
= "standard";
1855 visible
= (uri
== NULL
);
1856 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1857 gtk_action_group_set_visible (action_group
, visible
);
1859 group_name
= "lockdown-printing";
1860 visible
= (uri
== NULL
) && !web_view
->priv
->disable_printing
;
1861 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1862 gtk_action_group_set_visible (action_group
, visible
);
1864 group_name
= "lockdown-save-to-disk";
1865 visible
= (uri
== NULL
) && !web_view
->priv
->disable_save_to_disk
;
1866 action_group
= e_web_view_get_action_group (web_view
, group_name
);
1867 gtk_action_group_set_visible (action_group
, visible
);
1871 web_view_submit_alert (EAlertSink
*alert_sink
,
1877 const gchar
*icon_name
= NULL
;
1878 const gchar
*primary_text
;
1879 const gchar
*secondary_text
;
1880 gint icon_width
, icon_height
;
1883 web_view
= E_WEB_VIEW (alert_sink
);
1885 parent
= gtk_widget_get_toplevel (GTK_WIDGET (web_view
));
1886 parent
= gtk_widget_is_toplevel (parent
) ? parent
: NULL
;
1888 switch (e_alert_get_message_type (alert
)) {
1889 case GTK_MESSAGE_INFO
:
1890 icon_name
= "dialog-information";
1893 case GTK_MESSAGE_WARNING
:
1894 icon_name
= "dialog-warning";
1897 case GTK_MESSAGE_ERROR
:
1898 icon_name
= "dialog-error";
1902 dialog
= e_alert_dialog_new (parent
, alert
);
1903 gtk_dialog_run (GTK_DIALOG (dialog
));
1904 gtk_widget_destroy (dialog
);
1908 /* Primary text is required. */
1909 primary_text
= e_alert_get_primary_text (alert
);
1910 g_return_if_fail (primary_text
!= NULL
);
1912 /* Secondary text is optional. */
1913 secondary_text
= e_alert_get_secondary_text (alert
);
1914 if (secondary_text
== NULL
)
1915 secondary_text
= "";
1917 if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG
, &icon_width
, &icon_height
)) {
1922 buffer
= g_string_sized_new (512);
1928 "<meta http-equiv=\"content-type\""
1929 " content=\"text/html; charset=utf-8\">"
1935 "<table bgcolor='#000000' width='100%'"
1936 " cellpadding='1' cellspacing='0'>"
1939 "<table bgcolor='#dddddd' width='100%' cellpadding='6'>"
1942 g_string_append_printf (
1946 "<img src='gtk-stock://%s/?size=%d' width=\"%dpx\" height=\"%dpx\"/>"
1948 "<td align='left' width='100%%'>"
1954 GTK_ICON_SIZE_DIALOG
,
1969 e_web_view_load_string (web_view
, buffer
->str
);
1971 g_string_free (buffer
, TRUE
);
1975 web_view_can_execute_editing_command_cb (WebKitWebView
*webkit_web_view
,
1976 GAsyncResult
*result
,
1979 gboolean can_do_command
;
1981 can_do_command
= webkit_web_view_can_execute_editing_command_finish (
1982 webkit_web_view
, result
, NULL
);
1984 gtk_action_set_sensitive (action
, can_do_command
);
1985 g_object_unref (action
);
1989 web_view_selectable_update_actions (ESelectable
*selectable
,
1990 EFocusTracker
*focus_tracker
,
1991 GdkAtom
*clipboard_targets
,
1992 gint n_clipboard_targets
)
1996 gboolean can_copy
= FALSE
;
1998 web_view
= E_WEB_VIEW (selectable
);
2000 can_copy
= (e_web_view_get_clipboard_flags (web_view
) & E_CLIPBOARD_CAN_COPY
) != 0;
2002 action
= e_focus_tracker_get_copy_clipboard_action (focus_tracker
);
2003 gtk_action_set_sensitive (action
, can_copy
);
2004 gtk_action_set_tooltip (action
, _("Copy the selection"));
2006 action
= e_focus_tracker_get_cut_clipboard_action (focus_tracker
);
2007 webkit_web_view_can_execute_editing_command (
2008 WEBKIT_WEB_VIEW (web_view
),
2009 WEBKIT_EDITING_COMMAND_CUT
,
2010 NULL
, /* cancellable */
2011 (GAsyncReadyCallback
) web_view_can_execute_editing_command_cb
,
2012 g_object_ref (action
));
2013 gtk_action_set_tooltip (action
, _("Cut the selection"));
2015 action
= e_focus_tracker_get_paste_clipboard_action (focus_tracker
);
2016 webkit_web_view_can_execute_editing_command (
2017 WEBKIT_WEB_VIEW (web_view
),
2018 WEBKIT_EDITING_COMMAND_PASTE
,
2019 NULL
, /* cancellable */
2020 (GAsyncReadyCallback
) web_view_can_execute_editing_command_cb
,
2021 g_object_ref (action
));
2022 gtk_action_set_tooltip (action
, _("Paste the clipboard"));
2024 action
= e_focus_tracker_get_select_all_action (focus_tracker
);
2025 gtk_action_set_sensitive (action
, TRUE
);
2026 gtk_action_set_tooltip (action
, _("Select all text and images"));
2030 web_view_selectable_cut_clipboard (ESelectable
*selectable
)
2032 e_web_view_cut_clipboard (E_WEB_VIEW (selectable
));
2036 web_view_selectable_copy_clipboard (ESelectable
*selectable
)
2038 e_web_view_copy_clipboard (E_WEB_VIEW (selectable
));
2042 web_view_selectable_paste_clipboard (ESelectable
*selectable
)
2044 e_web_view_paste_clipboard (E_WEB_VIEW (selectable
));
2048 web_view_selectable_select_all (ESelectable
*selectable
)
2050 e_web_view_select_all (E_WEB_VIEW (selectable
));
2054 e_web_view_test_change_and_update_fonts_cb (EWebView
*web_view
,
2056 GSettings
*settings
)
2058 GVariant
*new_value
, *old_value
;
2060 new_value
= g_settings_get_value (settings
, key
);
2061 old_value
= g_hash_table_lookup (web_view
->priv
->old_settings
, key
);
2063 if (!new_value
|| !old_value
|| !g_variant_equal (new_value
, old_value
)) {
2065 g_hash_table_insert (web_view
->priv
->old_settings
, g_strdup (key
), new_value
);
2067 g_hash_table_remove (web_view
->priv
->old_settings
, key
);
2069 e_web_view_update_fonts (web_view
);
2070 } else if (new_value
) {
2071 g_variant_unref (new_value
);
2076 web_view_toplevel_event_after_cb (GtkWidget
*widget
,
2080 if (event
&& event
->type
== GDK_MOTION_NOTIFY
&& web_view
->priv
->has_hover_link
) {
2081 GdkEventMotion
*motion_event
= (GdkEventMotion
*) event
;
2083 if (gdk_event_get_window (event
) != gtk_widget_get_window (GTK_WIDGET (web_view
))) {
2084 GdkEventMotion fake_motion_event
;
2085 gboolean result
= FALSE
;
2087 fake_motion_event
= *motion_event
;
2088 fake_motion_event
.x
= -1.0;
2089 fake_motion_event
.y
= -1.0;
2090 fake_motion_event
.window
= gtk_widget_get_window (GTK_WIDGET (web_view
));
2092 /* Use a fake event instead of the call to unset the status message, because
2093 WebKit caches which link it stays on and doesn't emit the signal when still
2094 moving about the same link, thus this will unset the link also for the WebKit. */
2095 g_signal_emit_by_name (web_view
, "motion-notify-event", &fake_motion_event
, &result
);
2097 web_view
->priv
->has_hover_link
= FALSE
;
2103 web_view_map (GtkWidget
*widget
)
2105 GtkWidget
*toplevel
;
2107 toplevel
= gtk_widget_get_toplevel (widget
);
2109 g_signal_connect (toplevel
, "event-after", G_CALLBACK (web_view_toplevel_event_after_cb
), widget
);
2111 GTK_WIDGET_CLASS (e_web_view_parent_class
)->map (widget
);
2115 web_view_unmap (GtkWidget
*widget
)
2117 GtkWidget
*toplevel
;
2119 toplevel
= gtk_widget_get_toplevel (widget
);
2121 g_signal_handlers_disconnect_by_func (toplevel
, G_CALLBACK (web_view_toplevel_event_after_cb
), widget
);
2123 GTK_WIDGET_CLASS (e_web_view_parent_class
)->unmap (widget
);
2127 e_web_view_class_init (EWebViewClass
*class)
2129 GObjectClass
*object_class
;
2130 GtkWidgetClass
*widget_class
;
2132 g_type_class_add_private (class, sizeof (EWebViewPrivate
));
2134 object_class
= G_OBJECT_CLASS (class);
2135 object_class
->constructor
= web_view_constructor
;
2136 object_class
->set_property
= web_view_set_property
;
2137 object_class
->get_property
= web_view_get_property
;
2138 object_class
->dispose
= web_view_dispose
;
2139 object_class
->finalize
= web_view_finalize
;
2140 object_class
->constructed
= web_view_constructed
;
2142 widget_class
= GTK_WIDGET_CLASS (class);
2143 widget_class
->scroll_event
= web_view_scroll_event
;
2144 widget_class
->drag_motion
= web_view_drag_motion
;
2145 widget_class
->drag_drop
= web_view_drag_drop
;
2146 widget_class
->drag_leave
= web_view_drag_leave
;
2147 widget_class
->map
= web_view_map
;
2148 widget_class
->unmap
= web_view_unmap
;
2150 class->hovering_over_link
= web_view_hovering_over_link
;
2151 class->link_clicked
= web_view_link_clicked
;
2152 class->load_string
= web_view_load_string
;
2153 class->load_uri
= web_view_load_uri
;
2154 class->suggest_filename
= web_view_suggest_filename
;
2155 class->popup_event
= web_view_popup_event
;
2156 class->stop_loading
= web_view_stop_loading
;
2157 class->update_actions
= web_view_update_actions
;
2159 g_object_class_install_property (
2162 g_param_spec_boolean (
2167 G_PARAM_READWRITE
));
2169 g_object_class_install_property (
2171 PROP_CLIPBOARD_FLAGS
,
2178 G_PARAM_CONSTRUCT
));
2180 /* Inherited from ESelectableInterface; just a fake property here */
2181 g_object_class_override_property (
2183 PROP_COPY_TARGET_LIST
,
2184 "copy-target-list");
2186 /* Inherited from ESelectableInterface; just a fake property here */
2187 g_object_class_override_property (
2189 PROP_PASTE_TARGET_LIST
,
2190 "paste-target-list");
2192 g_object_class_install_property (
2194 PROP_CURSOR_IMAGE_SRC
,
2195 g_param_spec_string (
2197 "Image source uri at the mouse cursor",
2200 G_PARAM_READWRITE
));
2202 g_object_class_install_property (
2204 PROP_DISABLE_PRINTING
,
2205 g_param_spec_boolean (
2211 G_PARAM_CONSTRUCT
));
2213 g_object_class_install_property (
2215 PROP_DISABLE_SAVE_TO_DISK
,
2216 g_param_spec_boolean (
2217 "disable-save-to-disk",
2218 "Disable Save-to-Disk",
2222 G_PARAM_CONSTRUCT
));
2224 g_object_class_install_property (
2227 g_param_spec_boolean (
2233 G_PARAM_CONSTRUCT
));
2235 g_object_class_install_property (
2238 g_param_spec_object (
2243 G_PARAM_READWRITE
));
2245 g_object_class_install_property (
2248 g_param_spec_object (
2253 G_PARAM_READWRITE
));
2255 g_object_class_install_property (
2258 g_param_spec_object (
2263 G_PARAM_READWRITE
));
2265 g_object_class_install_property (
2268 g_param_spec_string (
2273 G_PARAM_READWRITE
));
2275 signals
[NEW_ACTIVITY
] = g_signal_new (
2277 G_TYPE_FROM_CLASS (class),
2279 G_STRUCT_OFFSET (EWebViewClass
, new_activity
),
2281 g_cclosure_marshal_VOID__OBJECT
,
2285 signals
[POPUP_EVENT
] = g_signal_new (
2287 G_TYPE_FROM_CLASS (class),
2289 G_STRUCT_OFFSET (EWebViewClass
, popup_event
),
2290 g_signal_accumulator_true_handled
, NULL
,
2292 G_TYPE_BOOLEAN
, 2, G_TYPE_STRING
, GDK_TYPE_EVENT
| G_SIGNAL_TYPE_STATIC_SCOPE
);
2294 signals
[STATUS_MESSAGE
] = g_signal_new (
2296 G_TYPE_FROM_CLASS (class),
2298 G_STRUCT_OFFSET (EWebViewClass
, status_message
),
2300 g_cclosure_marshal_VOID__STRING
,
2304 signals
[STOP_LOADING
] = g_signal_new (
2306 G_TYPE_FROM_CLASS (class),
2308 G_STRUCT_OFFSET (EWebViewClass
, stop_loading
),
2310 g_cclosure_marshal_VOID__VOID
,
2313 signals
[UPDATE_ACTIONS
] = g_signal_new (
2315 G_TYPE_FROM_CLASS (class),
2317 G_STRUCT_OFFSET (EWebViewClass
, update_actions
),
2319 g_cclosure_marshal_VOID__VOID
,
2322 /* return TRUE when a signal handler processed the mailto URI */
2323 signals
[PROCESS_MAILTO
] = g_signal_new (
2325 G_TYPE_FROM_CLASS (class),
2327 G_STRUCT_OFFSET (EWebViewClass
, process_mailto
),
2329 e_marshal_BOOLEAN__STRING
,
2330 G_TYPE_BOOLEAN
, 1, G_TYPE_STRING
);
2332 /* Expects an empty string to abandon the request,
2333 or NULL to keep the passed-in uri,
2334 or a new uri to load instead. */
2335 signals
[URI_REQUESTED
] = g_signal_new (
2337 G_TYPE_FROM_CLASS (class),
2339 G_STRUCT_OFFSET (EWebViewClass
, uri_requested
),
2341 G_TYPE_NONE
, 2, G_TYPE_STRING
, G_TYPE_POINTER
);
2345 e_web_view_alert_sink_init (EAlertSinkInterface
*iface
)
2347 iface
->submit_alert
= web_view_submit_alert
;
2351 e_web_view_selectable_init (ESelectableInterface
*iface
)
2353 iface
->update_actions
= web_view_selectable_update_actions
;
2354 iface
->cut_clipboard
= web_view_selectable_cut_clipboard
;
2355 iface
->copy_clipboard
= web_view_selectable_copy_clipboard
;
2356 iface
->paste_clipboard
= web_view_selectable_paste_clipboard
;
2357 iface
->select_all
= web_view_selectable_select_all
;
2361 initialize_web_extensions_cb (WebKitWebContext
*web_context
)
2363 /* Set the web extensions dir before the process is launched */
2364 webkit_web_context_set_web_extensions_directory (
2365 web_context
, EVOLUTION_WEB_EXTENSIONS_DIR
);
2369 e_web_view_init (EWebView
*web_view
)
2371 GtkUIManager
*ui_manager
;
2372 GtkActionGroup
*action_group
;
2373 EPopupAction
*popup_action
;
2374 GSettingsSchema
*settings_schema
;
2375 GSettings
*settings
;
2376 const gchar
*domain
= GETTEXT_PACKAGE
;
2379 GError
*error
= NULL
;
2381 web_view
->priv
= E_WEB_VIEW_GET_PRIVATE (web_view
);
2383 web_view
->priv
->old_settings
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_variant_unref
);
2386 web_view
, "context-menu",
2387 G_CALLBACK (web_view_context_menu_cb
), NULL
);
2390 web_view
, "mouse-target-changed",
2391 G_CALLBACK (web_view_mouse_target_changed_cb
), NULL
);
2394 web_view
, "decide-policy",
2395 G_CALLBACK (web_view_decide_policy_cb
),
2399 webkit_web_context_get_default (), "initialize-web-extensions",
2400 G_CALLBACK (initialize_web_extensions_cb
), NULL
);
2403 web_view
, "load-changed",
2404 G_CALLBACK (web_view_load_changed_cb
), NULL
);
2407 web_view
, "style-updated",
2408 G_CALLBACK (style_updated_cb
), NULL
);
2411 web_view
, "state-flags-changed",
2412 G_CALLBACK (style_updated_cb
), NULL
);
2414 ui_manager
= gtk_ui_manager_new ();
2415 web_view
->priv
->ui_manager
= ui_manager
;
2417 g_signal_connect_swapped (
2418 ui_manager
, "connect-proxy",
2419 G_CALLBACK (web_view_connect_proxy_cb
), web_view
);
2421 web_view_watch_web_extension (web_view
);
2423 settings
= e_util_ref_settings ("org.gnome.desktop.interface");
2424 web_view
->priv
->font_settings
= g_object_ref (settings
);
2425 handler_id
= g_signal_connect_swapped (
2426 settings
, "changed::font-name",
2427 G_CALLBACK (e_web_view_test_change_and_update_fonts_cb
), web_view
);
2428 web_view
->priv
->font_name_changed_handler_id
= handler_id
;
2429 handler_id
= g_signal_connect_swapped (
2430 settings
, "changed::monospace-font-name",
2431 G_CALLBACK (e_web_view_test_change_and_update_fonts_cb
), web_view
);
2432 web_view
->priv
->monospace_font_name_changed_handler_id
= handler_id
;
2433 g_object_unref (settings
);
2435 /* This schema is optional. Use if available. */
2436 id
= "org.gnome.settings-daemon.plugins.xsettings";
2437 settings_schema
= g_settings_schema_source_lookup (
2438 g_settings_schema_source_get_default (), id
, FALSE
);
2439 if (settings_schema
!= NULL
) {
2440 settings
= e_util_ref_settings (id
);
2441 web_view
->priv
->aliasing_settings
= g_object_ref (settings
);
2442 handler_id
= g_signal_connect_swapped (
2443 settings
, "changed::antialiasing",
2444 G_CALLBACK (e_web_view_test_change_and_update_fonts_cb
), web_view
);
2445 web_view
->priv
->antialiasing_changed_handler_id
= handler_id
;
2446 g_object_unref (settings
);
2447 g_settings_schema_unref (settings_schema
);
2450 action_group
= gtk_action_group_new ("uri");
2451 gtk_action_group_set_translation_domain (action_group
, domain
);
2452 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2453 g_object_unref (action_group
);
2455 gtk_action_group_add_actions (
2456 action_group
, uri_entries
,
2457 G_N_ELEMENTS (uri_entries
), web_view
);
2459 action_group
= gtk_action_group_new ("http");
2460 gtk_action_group_set_translation_domain (action_group
, domain
);
2461 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2462 g_object_unref (action_group
);
2464 gtk_action_group_add_actions (
2465 action_group
, http_entries
,
2466 G_N_ELEMENTS (http_entries
), web_view
);
2468 action_group
= gtk_action_group_new ("mailto");
2469 gtk_action_group_set_translation_domain (action_group
, domain
);
2470 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2471 g_object_unref (action_group
);
2473 gtk_action_group_add_actions (
2474 action_group
, mailto_entries
,
2475 G_N_ELEMENTS (mailto_entries
), web_view
);
2477 action_group
= gtk_action_group_new ("image");
2478 gtk_action_group_set_translation_domain (action_group
, domain
);
2479 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2480 g_object_unref (action_group
);
2482 gtk_action_group_add_actions (
2483 action_group
, image_entries
,
2484 G_N_ELEMENTS (image_entries
), web_view
);
2486 action_group
= gtk_action_group_new ("selection");
2487 gtk_action_group_set_translation_domain (action_group
, domain
);
2488 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2489 g_object_unref (action_group
);
2491 gtk_action_group_add_actions (
2492 action_group
, selection_entries
,
2493 G_N_ELEMENTS (selection_entries
), web_view
);
2495 action_group
= gtk_action_group_new ("standard");
2496 gtk_action_group_set_translation_domain (action_group
, domain
);
2497 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2498 g_object_unref (action_group
);
2500 gtk_action_group_add_actions (
2501 action_group
, standard_entries
,
2502 G_N_ELEMENTS (standard_entries
), web_view
);
2504 popup_action
= e_popup_action_new ("open");
2505 gtk_action_group_add_action (action_group
, GTK_ACTION (popup_action
));
2506 g_object_unref (popup_action
);
2508 e_binding_bind_property (
2509 web_view
, "open-proxy",
2510 popup_action
, "related-action",
2511 G_BINDING_BIDIRECTIONAL
|
2512 G_BINDING_SYNC_CREATE
);
2514 /* Support lockdown. */
2516 action_group
= gtk_action_group_new ("lockdown-printing");
2517 gtk_action_group_set_translation_domain (action_group
, domain
);
2518 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2519 g_object_unref (action_group
);
2521 popup_action
= e_popup_action_new ("print");
2522 gtk_action_group_add_action (action_group
, GTK_ACTION (popup_action
));
2523 g_object_unref (popup_action
);
2525 e_binding_bind_property (
2526 web_view
, "print-proxy",
2527 popup_action
, "related-action",
2528 G_BINDING_BIDIRECTIONAL
|
2529 G_BINDING_SYNC_CREATE
);
2531 action_group
= gtk_action_group_new ("lockdown-save-to-disk");
2532 gtk_action_group_set_translation_domain (action_group
, domain
);
2533 gtk_ui_manager_insert_action_group (ui_manager
, action_group
, 0);
2534 g_object_unref (action_group
);
2536 popup_action
= e_popup_action_new ("save-as");
2537 gtk_action_group_add_action (action_group
, GTK_ACTION (popup_action
));
2538 g_object_unref (popup_action
);
2540 e_binding_bind_property (
2541 web_view
, "save-as-proxy",
2542 popup_action
, "related-action",
2543 G_BINDING_BIDIRECTIONAL
|
2544 G_BINDING_SYNC_CREATE
);
2546 /* Because we are loading from a hard-coded string, there is
2547 * no chance of I/O errors. Failure here implies a malformed
2548 * UI definition. Full stop. */
2549 gtk_ui_manager_add_ui_from_string (ui_manager
, ui
, -1, &error
);
2551 g_error ("%s", error
->message
);
2553 id
= "org.gnome.evolution.webview";
2554 e_plugin_ui_register_manager (ui_manager
, id
, web_view
);
2555 e_plugin_ui_enable_manager (ui_manager
, id
);
2557 web_view
->priv
->element_clicked_cbs
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) g_ptr_array_unref
);
2559 web_view
->priv
->load_cancellable
= NULL
;
2563 e_web_view_new (void)
2565 return g_object_new (
2571 e_web_view_clear (EWebView
*web_view
)
2573 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2575 e_web_view_replace_load_cancellable (web_view
, FALSE
);
2577 webkit_web_view_load_html (
2578 WEBKIT_WEB_VIEW (web_view
),
2581 "<body class=\"-e-web-view-background-color -e-web-view-text-color\"></body>"
2587 e_web_view_load_string (EWebView
*web_view
,
2588 const gchar
*string
)
2590 EWebViewClass
*class;
2592 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2594 class = E_WEB_VIEW_GET_CLASS (web_view
);
2595 g_return_if_fail (class->load_string
!= NULL
);
2597 e_web_view_replace_load_cancellable (web_view
, TRUE
);
2599 class->load_string (web_view
, string
);
2603 e_web_view_load_uri (EWebView
*web_view
,
2606 EWebViewClass
*class;
2608 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2610 class = E_WEB_VIEW_GET_CLASS (web_view
);
2611 g_return_if_fail (class->load_uri
!= NULL
);
2613 e_web_view_replace_load_cancellable (web_view
, TRUE
);
2615 class->load_uri (web_view
, uri
);
2619 * e_web_view_suggest_filename:
2620 * @web_view: an #EWebView
2621 * @uri: a URI string
2623 * Attempts to derive a suggested filename from the @uri for use in a
2626 * By default the suggested filename is the last path segment of the @uri
2627 * (unless @uri looks like a query), but subclasses can use other mechanisms
2628 * for custom URI schemes. For example, "cid:" URIs in an email message may
2629 * refer to a MIME part with a suggested filename in its Content-Disposition
2632 * The returned string should be freed with g_free() when finished with it,
2633 * but callers should also be prepared for the function to return %NULL if
2634 * a filename cannot be determined.
2636 * Returns: a suggested filename, or %NULL
2639 e_web_view_suggest_filename (EWebView
*web_view
,
2642 EWebViewClass
*class;
2645 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2646 g_return_val_if_fail (uri
!= NULL
, NULL
);
2648 class = E_WEB_VIEW_GET_CLASS (web_view
);
2649 g_return_val_if_fail (class->suggest_filename
!= NULL
, NULL
);
2651 filename
= class->suggest_filename (web_view
, uri
);
2653 if (filename
!= NULL
)
2654 e_filename_make_safe (filename
);
2660 e_web_view_reload (EWebView
*web_view
)
2662 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2664 e_web_view_replace_load_cancellable (web_view
, TRUE
);
2666 webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view
));
2670 get_document_content_html_cb (GObject
*source_object
,
2671 GAsyncResult
*result
,
2674 GDBusProxy
*web_extension
;
2675 GTask
*task
= user_data
;
2676 GVariant
*result_variant
;
2677 gchar
*html_content
= NULL
;
2678 GError
*error
= NULL
;
2680 g_return_if_fail (G_IS_DBUS_PROXY (source_object
));
2681 g_return_if_fail (G_IS_TASK (task
));
2683 web_extension
= G_DBUS_PROXY (source_object
);
2685 result_variant
= g_dbus_proxy_call_finish (web_extension
, result
, &error
);
2687 g_variant_get (result_variant
, "(s)", &html_content
);
2688 g_variant_unref (result_variant
);
2690 g_task_return_pointer (task
, html_content
, g_free
);
2691 g_object_unref (task
);
2694 g_dbus_error_strip_remote_error (error
);
2696 e_util_claim_dbus_proxy_call_error (web_extension
, "GetDocumentContentHTML", error
);
2697 g_clear_error (&error
);
2701 e_web_view_get_content_html (EWebView
*web_view
,
2702 GCancellable
*cancellable
,
2703 GAsyncReadyCallback callback
,
2706 GDBusProxy
*web_extension
;
2709 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2711 task
= g_task_new (web_view
, cancellable
, callback
, user_data
);
2713 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
2714 if (web_extension
) {
2717 "GetDocumentContentHTML",
2720 webkit_web_view_get_page_id (
2721 WEBKIT_WEB_VIEW (web_view
))),
2722 G_DBUS_CALL_FLAGS_NONE
,
2725 get_document_content_html_cb
,
2726 g_object_ref (task
));
2728 g_task_return_pointer (task
, NULL
, NULL
);
2732 e_web_view_get_content_html_finish (EWebView
*web_view
,
2733 GAsyncResult
*result
,
2736 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2737 g_return_val_if_fail (g_task_is_valid (result
, web_view
), FALSE
);
2739 return g_task_propagate_pointer (G_TASK (result
), error
);
2743 e_web_view_get_content_html_sync (EWebView
*web_view
,
2744 GCancellable
*cancellable
,
2747 GDBusProxy
*web_extension
;
2749 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2751 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
2752 if (web_extension
) {
2755 result
= e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
2757 "GetDocumentContentHTML",
2760 webkit_web_view_get_page_id (
2761 WEBKIT_WEB_VIEW (web_view
))),
2762 G_DBUS_CALL_FLAGS_NONE
,
2768 gchar
*html_content
= NULL
;
2770 g_variant_get (result
, "(s)", &html_content
);
2771 g_variant_unref (result
);
2773 return html_content
;
2781 e_web_view_get_caret_mode (EWebView
*web_view
)
2783 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
2785 return web_view
->priv
->caret_mode
;
2789 e_web_view_set_caret_mode (EWebView
*web_view
,
2790 gboolean caret_mode
)
2792 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2794 if (web_view
->priv
->caret_mode
== caret_mode
)
2797 web_view
->priv
->caret_mode
= caret_mode
;
2799 g_object_notify (G_OBJECT (web_view
), "caret-mode");
2803 e_web_view_get_copy_target_list (EWebView
*web_view
)
2805 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2809 /*return webkit_web_view_get_copy_target_list (
2810 WEBKIT_WEB_VIEW (web_view));*/
2814 e_web_view_get_disable_printing (EWebView
*web_view
)
2816 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
2818 return web_view
->priv
->disable_printing
;
2822 e_web_view_set_disable_printing (EWebView
*web_view
,
2823 gboolean disable_printing
)
2825 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2827 if (web_view
->priv
->disable_printing
== disable_printing
)
2830 web_view
->priv
->disable_printing
= disable_printing
;
2832 g_object_notify (G_OBJECT (web_view
), "disable-printing");
2836 e_web_view_get_disable_save_to_disk (EWebView
*web_view
)
2838 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
2840 return web_view
->priv
->disable_save_to_disk
;
2844 e_web_view_set_disable_save_to_disk (EWebView
*web_view
,
2845 gboolean disable_save_to_disk
)
2847 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2849 if (web_view
->priv
->disable_save_to_disk
== disable_save_to_disk
)
2852 web_view
->priv
->disable_save_to_disk
= disable_save_to_disk
;
2854 g_object_notify (G_OBJECT (web_view
), "disable-save-to-disk");
2858 e_web_view_get_editable (EWebView
*web_view
)
2860 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
2862 return webkit_web_view_is_editable (WEBKIT_WEB_VIEW (web_view
));
2866 e_web_view_set_editable (EWebView
*web_view
,
2869 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2871 webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view
), editable
);
2875 e_web_view_get_clipboard_flags (EWebView
*web_view
)
2877 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), 0);
2879 return web_view
->priv
->clipboard_flags
;
2883 e_web_view_set_clipboard_flags (EWebView
*web_view
,
2884 guint32 clipboard_flags
)
2886 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2888 if (web_view
->priv
->clipboard_flags
== clipboard_flags
)
2891 web_view
->priv
->clipboard_flags
= clipboard_flags
;
2893 g_object_notify (G_OBJECT (web_view
), "clipboard-flags");
2897 e_web_view_get_need_input (EWebView
*web_view
)
2899 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
2901 return web_view
->priv
->need_input
;
2905 e_web_view_set_need_input (EWebView
*web_view
,
2906 gboolean need_input
)
2908 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2910 if ((!web_view
->priv
->need_input
) == (!need_input
))
2913 web_view
->priv
->need_input
= need_input
;
2915 g_object_notify (G_OBJECT (web_view
), "need-input");
2919 e_web_view_get_selected_uri (EWebView
*web_view
)
2921 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2923 return web_view
->priv
->selected_uri
;
2927 e_web_view_set_selected_uri (EWebView
*web_view
,
2928 const gchar
*selected_uri
)
2930 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2932 if (g_strcmp0 (web_view
->priv
->selected_uri
, selected_uri
) == 0)
2935 g_free (web_view
->priv
->selected_uri
);
2936 web_view
->priv
->selected_uri
= g_strdup (selected_uri
);
2938 g_object_notify (G_OBJECT (web_view
), "selected-uri");
2942 e_web_view_get_cursor_image_src (EWebView
*web_view
)
2944 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2946 return web_view
->priv
->cursor_image_src
;
2950 e_web_view_set_cursor_image_src (EWebView
*web_view
,
2951 const gchar
*src_uri
)
2953 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2955 if (g_strcmp0 (web_view
->priv
->cursor_image_src
, src_uri
) == 0)
2958 g_free (web_view
->priv
->cursor_image_src
);
2959 web_view
->priv
->cursor_image_src
= g_strdup (src_uri
);
2961 g_object_notify (G_OBJECT (web_view
), "cursor-image-src");
2965 e_web_view_get_open_proxy (EWebView
*web_view
)
2967 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
2969 return web_view
->priv
->open_proxy
;
2973 e_web_view_set_open_proxy (EWebView
*web_view
,
2974 GtkAction
*open_proxy
)
2976 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
2978 if (web_view
->priv
->open_proxy
== open_proxy
)
2981 if (open_proxy
!= NULL
) {
2982 g_return_if_fail (GTK_IS_ACTION (open_proxy
));
2983 g_object_ref (open_proxy
);
2986 if (web_view
->priv
->open_proxy
!= NULL
)
2987 g_object_unref (web_view
->priv
->open_proxy
);
2989 web_view
->priv
->open_proxy
= open_proxy
;
2991 g_object_notify (G_OBJECT (web_view
), "open-proxy");
2995 e_web_view_get_paste_target_list (EWebView
*web_view
)
2997 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3000 return webkit_web_view_get_paste_target_list (
3001 WEBKIT_WEB_VIEW (web_view)); */
3006 e_web_view_get_print_proxy (EWebView
*web_view
)
3008 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3010 return web_view
->priv
->print_proxy
;
3014 e_web_view_set_print_proxy (EWebView
*web_view
,
3015 GtkAction
*print_proxy
)
3017 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3019 if (web_view
->priv
->print_proxy
== print_proxy
)
3022 if (print_proxy
!= NULL
) {
3023 g_return_if_fail (GTK_IS_ACTION (print_proxy
));
3024 g_object_ref (print_proxy
);
3027 if (web_view
->priv
->print_proxy
!= NULL
)
3028 g_object_unref (web_view
->priv
->print_proxy
);
3030 web_view
->priv
->print_proxy
= print_proxy
;
3032 g_object_notify (G_OBJECT (web_view
), "print-proxy");
3036 e_web_view_get_save_as_proxy (EWebView
*web_view
)
3038 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3040 return web_view
->priv
->save_as_proxy
;
3044 e_web_view_set_save_as_proxy (EWebView
*web_view
,
3045 GtkAction
*save_as_proxy
)
3047 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3049 if (web_view
->priv
->save_as_proxy
== save_as_proxy
)
3052 if (save_as_proxy
!= NULL
) {
3053 g_return_if_fail (GTK_IS_ACTION (save_as_proxy
));
3054 g_object_ref (save_as_proxy
);
3057 if (web_view
->priv
->save_as_proxy
!= NULL
)
3058 g_object_unref (web_view
->priv
->save_as_proxy
);
3060 web_view
->priv
->save_as_proxy
= save_as_proxy
;
3062 g_object_notify (G_OBJECT (web_view
), "save-as-proxy");
3066 e_web_view_add_highlight (EWebView
*web_view
,
3067 const gchar
*highlight
)
3069 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3070 g_return_if_fail (highlight
&& *highlight
);
3073 &web_view
->priv
->highlights
,
3074 g_strdup (highlight
));
3076 webkit_find_controller_search (
3077 web_view
->priv
->find_controller
,
3079 WEBKIT_FIND_OPTIONS_NONE
,
3084 e_web_view_clear_highlights (EWebView
*web_view
)
3086 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3088 webkit_find_controller_search_finish (web_view
->priv
->find_controller
);
3090 while (!g_queue_is_empty (&web_view
->priv
->highlights
))
3091 g_free (g_queue_pop_head (&web_view
->priv
->highlights
));
3095 e_web_view_update_highlights (EWebView
*web_view
)
3097 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3099 web_view_update_document_highlights (web_view
);
3103 e_web_view_get_action (EWebView
*web_view
,
3104 const gchar
*action_name
)
3106 GtkUIManager
*ui_manager
;
3108 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3109 g_return_val_if_fail (action_name
!= NULL
, NULL
);
3111 ui_manager
= e_web_view_get_ui_manager (web_view
);
3113 return e_lookup_action (ui_manager
, action_name
);
3117 e_web_view_get_action_group (EWebView
*web_view
,
3118 const gchar
*group_name
)
3120 GtkUIManager
*ui_manager
;
3122 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3123 g_return_val_if_fail (group_name
!= NULL
, NULL
);
3125 ui_manager
= e_web_view_get_ui_manager (web_view
);
3127 return e_lookup_action_group (ui_manager
, group_name
);
3131 e_web_view_copy_clipboard (EWebView
*web_view
)
3133 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3135 webkit_web_view_execute_editing_command (
3136 WEBKIT_WEB_VIEW (web_view
), WEBKIT_EDITING_COMMAND_COPY
);
3140 e_web_view_cut_clipboard (EWebView
*web_view
)
3142 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3144 webkit_web_view_execute_editing_command (
3145 WEBKIT_WEB_VIEW (web_view
), WEBKIT_EDITING_COMMAND_CUT
);
3149 e_web_view_is_selection_active (EWebView
*web_view
)
3151 GDBusProxy
*web_extension
;
3153 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
3155 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
3156 if (web_extension
) {
3159 result
= e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
3161 "DocumentHasSelection",
3164 webkit_web_view_get_page_id (
3165 WEBKIT_WEB_VIEW (web_view
))),
3169 gboolean value
= FALSE
;
3171 g_variant_get (result
, "(b)", &value
);
3172 g_variant_unref (result
);
3181 e_web_view_paste_clipboard (EWebView
*web_view
)
3183 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3185 webkit_web_view_execute_editing_command (
3186 WEBKIT_WEB_VIEW (web_view
), WEBKIT_EDITING_COMMAND_PASTE
);
3190 e_web_view_scroll_forward (EWebView
*web_view
)
3192 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
3194 webkit_web_view_move_cursor (
3195 WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, 1);
3197 return TRUE
; /* XXX This means nothing. */
3201 e_web_view_scroll_backward (EWebView
*web_view
)
3203 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), FALSE
);
3205 webkit_web_view_move_cursor (
3206 WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, -1);
3208 return TRUE
; /* XXX This means nothing. */
3212 e_web_view_select_all (EWebView
*web_view
)
3214 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3216 webkit_web_view_execute_editing_command (
3217 WEBKIT_WEB_VIEW (web_view
), WEBKIT_EDITING_COMMAND_SELECT_ALL
);
3221 e_web_view_unselect_all (EWebView
*web_view
)
3224 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3226 gtk_html_command (GTK_HTML (web_view
), "unselect-all");
3231 e_web_view_zoom_100 (EWebView
*web_view
)
3233 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3235 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view
), 1.0);
3239 e_web_view_zoom_in (EWebView
*web_view
)
3243 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3245 /* There is no webkit_web_view_zoom_in function in WK2, so emulate it */
3246 zoom_level
= webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view
));
3247 /* zoom-step in WK1 was 0.1 */
3249 if (zoom_level
< 4.9999)
3250 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view
), zoom_level
);
3254 e_web_view_zoom_out (EWebView
*web_view
)
3258 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3260 /* There is no webkit_web_view_zoom_out function in WK2, so emulate it */
3261 zoom_level
= webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view
));
3262 /* zoom-step in WK1 was 0.1 */
3264 if (zoom_level
> 0.7999)
3265 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view
), zoom_level
);
3269 e_web_view_get_ui_manager (EWebView
*web_view
)
3271 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3273 return web_view
->priv
->ui_manager
;
3277 e_web_view_popup_menu_deactivate_cb (GtkMenu
*popup_menu
,
3278 GtkWidget
*web_view
)
3280 g_return_if_fail (GTK_IS_MENU (popup_menu
));
3282 g_signal_handlers_disconnect_by_func (popup_menu
, e_web_view_popup_menu_deactivate_cb
, web_view
);
3283 gtk_menu_detach (popup_menu
);
3287 e_web_view_get_popup_menu (EWebView
*web_view
)
3289 GtkUIManager
*ui_manager
;
3292 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3294 ui_manager
= e_web_view_get_ui_manager (web_view
);
3295 menu
= gtk_ui_manager_get_widget (ui_manager
, "/context");
3296 g_return_val_if_fail (GTK_IS_MENU (menu
), NULL
);
3298 g_warn_if_fail (!gtk_menu_get_attach_widget (GTK_MENU (menu
)));
3300 gtk_menu_attach_to_widget (GTK_MENU (menu
),
3301 GTK_WIDGET (web_view
),
3306 G_CALLBACK (e_web_view_popup_menu_deactivate_cb
), web_view
);
3312 e_web_view_show_popup_menu (EWebView
*web_view
,
3317 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3319 e_web_view_update_actions (web_view
);
3321 menu
= e_web_view_get_popup_menu (web_view
);
3323 gtk_menu_popup_at_pointer (GTK_MENU (menu
), event
);
3327 * e_web_view_new_activity:
3328 * @web_view: an #EWebView
3330 * Returns a new #EActivity for an #EWebView-related asynchronous operation,
3331 * and emits the #EWebView::new-activity signal. By default the #EActivity
3332 * comes loaded with a #GCancellable and sets the @web_view itself as the
3333 * #EActivity:alert-sink (which means alerts are displayed directly in the
3334 * content area). The signal emission allows the #EActivity to be further
3335 * customized and/or tracked by the application.
3337 * Returns: an #EActivity
3340 e_web_view_new_activity (EWebView
*web_view
)
3342 EActivity
*activity
;
3343 EAlertSink
*alert_sink
;
3344 GCancellable
*cancellable
;
3346 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3348 activity
= e_activity_new ();
3350 alert_sink
= E_ALERT_SINK (web_view
);
3351 e_activity_set_alert_sink (activity
, alert_sink
);
3353 cancellable
= g_cancellable_new ();
3354 e_activity_set_cancellable (activity
, cancellable
);
3355 g_object_unref (cancellable
);
3357 g_signal_emit (web_view
, signals
[NEW_ACTIVITY
], 0, activity
);
3363 e_web_view_status_message (EWebView
*web_view
,
3364 const gchar
*status_message
)
3366 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3368 g_signal_emit (web_view
, signals
[STATUS_MESSAGE
], 0, status_message
);
3372 e_web_view_stop_loading (EWebView
*web_view
)
3374 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3376 g_signal_emit (web_view
, signals
[STOP_LOADING
], 0);
3380 e_web_view_update_actions (EWebView
*web_view
)
3382 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3384 g_signal_emit (web_view
, signals
[UPDATE_ACTIONS
], 0);
3388 get_selection_content_html_cb (GObject
*source_object
,
3389 GAsyncResult
*result
,
3392 GDBusProxy
*web_extension
;
3393 GTask
*task
= user_data
;
3394 GVariant
*result_variant
;
3395 gchar
*html_content
= NULL
;
3396 GError
*error
= NULL
;
3398 g_return_if_fail (G_IS_DBUS_PROXY (source_object
));
3399 g_return_if_fail (G_IS_TASK (task
));
3401 web_extension
= G_DBUS_PROXY (source_object
);
3403 result_variant
= g_dbus_proxy_call_finish (web_extension
, result
, &error
);
3405 g_variant_get (result_variant
, "(s)", &html_content
);
3406 g_variant_unref (result_variant
);
3408 g_task_return_pointer (task
, html_content
, g_free
);
3409 g_object_unref (task
);
3412 g_dbus_error_strip_remote_error (error
);
3414 e_util_claim_dbus_proxy_call_error (web_extension
, "GetSelectionContentHTML", error
);
3415 g_clear_error (&error
);
3419 e_web_view_get_selection_content_html (EWebView
*web_view
,
3420 GCancellable
*cancellable
,
3421 GAsyncReadyCallback callback
,
3424 GDBusProxy
*web_extension
;
3427 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3429 task
= g_task_new (web_view
, cancellable
, callback
, user_data
);
3431 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
3432 if (web_extension
) {
3435 "GetSelectionContentHTML",
3438 webkit_web_view_get_page_id (
3439 WEBKIT_WEB_VIEW (web_view
))),
3440 G_DBUS_CALL_FLAGS_NONE
,
3443 get_selection_content_html_cb
,
3444 g_object_ref (task
));
3446 g_task_return_pointer (task
, NULL
, NULL
);
3450 e_web_view_get_selection_content_html_finish (EWebView
*web_view
,
3451 GAsyncResult
*result
,
3454 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3455 g_return_val_if_fail (g_task_is_valid (result
, web_view
), FALSE
);
3457 return g_task_propagate_pointer (G_TASK (result
), error
);
3461 e_web_view_get_selection_content_html_sync (EWebView
*web_view
,
3462 GCancellable
*cancellable
,
3465 GDBusProxy
*web_extension
;
3467 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
3469 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
3470 if (web_extension
) {
3473 result
= e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
3475 "GetSelectionContentHTML",
3478 webkit_web_view_get_page_id (
3479 WEBKIT_WEB_VIEW (web_view
))),
3480 G_DBUS_CALL_FLAGS_NONE
,
3486 gchar
*html_content
= NULL
;
3488 g_variant_get (result
, "(s)", &html_content
);
3489 g_variant_unref (result
);
3490 return html_content
;
3498 e_web_view_get_citation_color_for_level (gint level
)
3500 /* Block quote border colors are borrowed from Thunderbird. */
3501 static const gchar
*citation_color_levels
[5] = {
3502 "rgb(233,185,110)", /* level 5 - Chocolate 1 */
3503 "rgb(114,159,207)", /* level 1 - Sky Blue 1 */
3504 "rgb(173,127,168)", /* level 2 - Plum 1 */
3505 "rgb(138,226,52)", /* level 3 - Chameleon 1 */
3506 "rgb(252,175,62)", /* level 4 - Orange 1 */
3509 g_return_val_if_fail (level
> 0, citation_color_levels
[1]);
3511 return citation_color_levels
[level
% 5];
3515 e_web_view_update_fonts_settings (GSettings
*font_settings
,
3516 GSettings
*aliasing_settings
,
3517 PangoFontDescription
*ms_font
,
3518 PangoFontDescription
*vw_font
,
3519 GtkWidget
*view_widget
)
3521 gboolean clean_ms
= FALSE
, clean_vw
= FALSE
;
3523 const gchar
*styles
[] = { "normal", "oblique", "italic" };
3524 const gchar
*smoothing
= NULL
;
3525 GdkColor
*link
= NULL
;
3526 GdkColor
*visited
= NULL
;
3527 GString
*stylesheet
;
3528 GtkStyleContext
*context
;
3529 PangoFontDescription
*min_size
, *ms
, *vw
;
3530 WebKitSettings
*wk_settings
;
3531 WebKitUserContentManager
*manager
;
3532 WebKitUserStyleSheet
*style_sheet
;
3537 font
= g_settings_get_string (
3539 "monospace-font-name");
3541 ms
= pango_font_description_from_string (
3542 (font
!= NULL
) ? font
: "monospace 10");
3553 font
= g_settings_get_string (
3557 vw
= pango_font_description_from_string (
3558 (font
!= NULL
) ? font
: "serif 10");
3566 if (pango_font_description_get_size (ms
) < pango_font_description_get_size (vw
))
3571 stylesheet
= g_string_new ("");
3572 g_string_append_printf (
3575 " font-family: '%s';\n"
3576 " font-size: %dpt;\n"
3577 " font-weight: %d;\n"
3578 " font-style: %s;\n",
3579 pango_font_description_get_family (vw
),
3580 pango_font_description_get_size (vw
) / PANGO_SCALE
,
3581 pango_font_description_get_weight (vw
),
3582 styles
[pango_font_description_get_style (vw
)]);
3584 if (aliasing_settings
!= NULL
)
3585 aa
= g_settings_get_string (
3586 aliasing_settings
, "antialiasing");
3588 if (g_strcmp0 (aa
, "none") == 0)
3590 else if (g_strcmp0 (aa
, "grayscale") == 0)
3591 smoothing
= "antialiased";
3592 else if (g_strcmp0 (aa
, "rgba") == 0)
3593 smoothing
= "subpixel-antialiased";
3595 if (smoothing
!= NULL
)
3596 g_string_append_printf (
3598 " -webkit-font-smoothing: %s;\n",
3603 g_string_append (stylesheet
, "}\n");
3605 g_string_append_printf (
3608 " font-family: '%s';\n"
3609 " font-size: %dpt;\n"
3610 " font-weight: %d;\n"
3611 " font-style: %s;\n"
3614 pango_font_description_get_family (ms
),
3615 pango_font_description_get_size (ms
) / PANGO_SCALE
,
3616 pango_font_description_get_weight (ms
),
3617 styles
[pango_font_description_get_style (ms
)]);
3620 context
= gtk_widget_get_style_context (view_widget
);
3621 gtk_style_context_get_style (
3623 "link-color", &link
,
3624 "visited-link-color", &visited
,
3629 GtkStateFlags state
;
3631 link
= g_slice_new0 (GdkColor
);
3632 link
->blue
= G_MAXINT16
;
3639 state
= gtk_style_context_get_state (context
);
3640 state
= state
& (~(GTK_STATE_FLAG_VISITED
| GTK_STATE_FLAG_LINK
));
3641 state
= state
| GTK_STATE_FLAG_LINK
;
3643 gtk_style_context_save (context
);
3644 gtk_style_context_set_state (context
, state
);
3645 gtk_style_context_get_color (context
, state
, &rgba
);
3646 gtk_style_context_restore (context
);
3648 e_rgba_to_color (&rgba
, link
);
3651 if (visited
== NULL
) {
3653 GtkStateFlags state
;
3655 visited
= g_slice_new0 (GdkColor
);
3656 visited
->red
= G_MAXINT16
;
3663 state
= gtk_style_context_get_state (context
);
3664 state
= state
& (~(GTK_STATE_FLAG_VISITED
| GTK_STATE_FLAG_LINK
));
3665 state
= state
| GTK_STATE_FLAG_VISITED
;
3667 gtk_style_context_save (context
);
3668 gtk_style_context_set_state (context
, state
);
3669 gtk_style_context_get_color (context
, state
, &rgba
);
3670 gtk_style_context_restore (context
);
3672 e_rgba_to_color (&rgba
, visited
);
3675 g_string_append_printf (
3683 e_color_to_value (link
),
3684 e_color_to_value (visited
));
3686 gdk_color_free (link
);
3687 gdk_color_free (visited
);
3691 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3693 " padding: 0ch 1ch 0ch 1ch;\n"
3695 " border-width: 0px 2px 0px 2px;\n"
3696 " border-style: none solid none solid;\n"
3697 " border-radius: 2px;\n"
3700 g_string_append_printf (
3702 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3704 " border-color: %s;\n"
3706 e_web_view_get_citation_color_for_level (1));
3708 g_string_append_printf (
3710 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3711 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3713 " border-color: %s;\n"
3715 e_web_view_get_citation_color_for_level (2));
3717 g_string_append_printf (
3719 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3720 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3721 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3723 " border-color: %s;\n"
3725 e_web_view_get_citation_color_for_level (3));
3727 g_string_append_printf (
3729 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3730 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3731 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3732 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3734 " border-color: %s;\n"
3736 e_web_view_get_citation_color_for_level (4));
3738 g_string_append_printf (
3740 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3741 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3742 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3743 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3744 "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
3746 " border-color: %s;\n"
3748 e_web_view_get_citation_color_for_level (5));
3751 wk_settings
= webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view_widget
));
3755 "default-font-size",
3756 e_util_normalize_font_size (
3757 view_widget
, pango_font_description_get_size (vw
) / PANGO_SCALE
),
3758 "default-font-family",
3759 pango_font_description_get_family (vw
),
3760 "monospace-font-family",
3761 pango_font_description_get_family (ms
),
3762 "default-monospace-font-size",
3763 e_util_normalize_font_size (
3764 view_widget
, pango_font_description_get_size (ms
) / PANGO_SCALE
),
3765 "minimum-font-size",
3766 e_util_normalize_font_size (
3767 view_widget
, pango_font_description_get_size (min_size
) / PANGO_SCALE
),
3770 manager
= webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (view_widget
));
3771 webkit_user_content_manager_remove_all_style_sheets (manager
);
3773 style_sheet
= webkit_user_style_sheet_new (
3775 WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES
,
3776 WEBKIT_USER_STYLE_LEVEL_USER
,
3780 webkit_user_content_manager_add_style_sheet (manager
, style_sheet
);
3782 webkit_user_style_sheet_unref (style_sheet
);
3784 g_string_free (stylesheet
, TRUE
);
3787 pango_font_description_free (ms
);
3789 pango_font_description_free (vw
);
3793 e_web_view_get_default_webkit_settings (void)
3795 return webkit_settings_new_with_settings (
3796 "auto-load-images", TRUE
,
3797 "default-charset", "utf-8",
3798 "enable-html5-database", FALSE
,
3799 "enable-dns-prefetching", FALSE
,
3800 "enable-html5-local-storage", FALSE
,
3801 "enable-java", FALSE
,
3802 "enable-javascript", FALSE
,
3803 "enable-offline-web-application-cache", FALSE
,
3804 "enable-page-cache", FALSE
,
3805 "enable-plugins", FALSE
,
3806 "enable-smooth-scrolling", FALSE
,
3807 "media-playback-allows-inline", FALSE
,
3812 e_web_view_update_fonts (EWebView
*web_view
)
3814 EWebViewClass
*class;
3815 PangoFontDescription
*ms
= NULL
, *vw
= NULL
;
3817 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3819 class = E_WEB_VIEW_GET_CLASS (web_view
);
3820 if (class->set_fonts
!= NULL
)
3821 class->set_fonts (web_view
, &ms
, &vw
);
3823 e_web_view_update_fonts_settings (
3824 web_view
->priv
->font_settings
,
3825 web_view
->priv
->aliasing_settings
,
3826 ms
, vw
, GTK_WIDGET (web_view
));
3828 pango_font_description_free (ms
);
3829 pango_font_description_free (vw
);
3832 /* Helper for e_web_view_cursor_image_copy() */
3834 web_view_cursor_image_copy_pixbuf_cb (GObject
*source_object
,
3835 GAsyncResult
*result
,
3838 EActivity
*activity
;
3839 EAlertSink
*alert_sink
;
3841 GError
*local_error
= NULL
;
3843 activity
= E_ACTIVITY (user_data
);
3844 alert_sink
= e_activity_get_alert_sink (activity
);
3846 pixbuf
= gdk_pixbuf_new_from_stream_finish (result
, &local_error
);
3850 ((pixbuf
!= NULL
) && (local_error
== NULL
)) ||
3851 ((pixbuf
== NULL
) && (local_error
!= NULL
)));
3853 if (e_activity_handle_cancellation (activity
, local_error
)) {
3854 g_error_free (local_error
);
3856 } else if (local_error
!= NULL
) {
3859 "widgets:no-image-copy",
3860 local_error
->message
, NULL
);
3861 g_error_free (local_error
);
3864 GtkClipboard
*clipboard
;
3866 clipboard
= gtk_clipboard_get (GDK_SELECTION_CLIPBOARD
);
3867 gtk_clipboard_set_image (clipboard
, pixbuf
);
3868 gtk_clipboard_store (clipboard
);
3870 e_activity_set_state (activity
, E_ACTIVITY_COMPLETED
);
3873 g_clear_object (&activity
);
3874 g_clear_object (&pixbuf
);
3877 /* Helper for e_web_view_cursor_image_copy() */
3879 web_view_cursor_image_copy_request_cb (GObject
*source_object
,
3880 GAsyncResult
*result
,
3883 EActivity
*activity
;
3884 EAlertSink
*alert_sink
;
3885 GCancellable
*cancellable
;
3886 GInputStream
*input_stream
;
3887 GError
*local_error
= NULL
;
3889 activity
= E_ACTIVITY (user_data
);
3890 alert_sink
= e_activity_get_alert_sink (activity
);
3891 cancellable
= e_activity_get_cancellable (activity
);
3893 input_stream
= e_web_view_request_finish (
3894 E_WEB_VIEW (source_object
), result
, &local_error
);
3898 ((input_stream
!= NULL
) && (local_error
== NULL
)) ||
3899 ((input_stream
== NULL
) && (local_error
!= NULL
)));
3901 if (e_activity_handle_cancellation (activity
, local_error
)) {
3902 g_error_free (local_error
);
3904 } else if (local_error
!= NULL
) {
3907 "widgets:no-image-copy",
3908 local_error
->message
, NULL
);
3909 g_error_free (local_error
);
3912 gdk_pixbuf_new_from_stream_async (
3913 input_stream
, cancellable
,
3914 web_view_cursor_image_copy_pixbuf_cb
,
3915 g_object_ref (activity
));
3918 g_clear_object (&activity
);
3919 g_clear_object (&input_stream
);
3923 * e_web_view_cursor_image_copy:
3924 * @web_view: an #EWebView
3926 * Asynchronously copies the image under the cursor to the clipboard.
3928 * This function triggers a #EWebView::new-activity signal emission so
3929 * the asynchronous operation can be tracked and/or cancelled.
3932 e_web_view_cursor_image_copy (EWebView
*web_view
)
3934 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
3936 if (web_view
->priv
->cursor_image_src
!= NULL
) {
3937 EActivity
*activity
;
3938 GCancellable
*cancellable
;
3941 activity
= e_web_view_new_activity (web_view
);
3942 cancellable
= e_activity_get_cancellable (activity
);
3944 text
= _("Copying image to clipboard");
3945 e_activity_set_text (activity
, text
);
3947 e_web_view_request (
3949 web_view
->priv
->cursor_image_src
,
3951 web_view_cursor_image_copy_request_cb
,
3952 g_object_ref (activity
));
3954 g_object_unref (activity
);
3958 /* Helper for e_web_view_cursor_image_save() */
3960 web_view_cursor_image_save_splice_cb (GObject
*source_object
,
3961 GAsyncResult
*result
,
3964 EActivity
*activity
;
3965 EAlertSink
*alert_sink
;
3966 AsyncContext
*async_context
;
3967 GError
*local_error
= NULL
;
3969 async_context
= (AsyncContext
*) user_data
;
3971 activity
= async_context
->activity
;
3972 alert_sink
= e_activity_get_alert_sink (activity
);
3974 g_output_stream_splice_finish (
3975 G_OUTPUT_STREAM (source_object
), result
, &local_error
);
3977 if (e_activity_handle_cancellation (activity
, local_error
)) {
3978 g_error_free (local_error
);
3980 } else if (local_error
!= NULL
) {
3983 "widgets:no-image-save",
3984 local_error
->message
, NULL
);
3985 g_error_free (local_error
);
3988 e_activity_set_state (activity
, E_ACTIVITY_COMPLETED
);
3991 async_context_free (async_context
);
3994 /* Helper for e_web_view_cursor_image_save() */
3996 web_view_cursor_image_save_replace_cb (GObject
*source_object
,
3997 GAsyncResult
*result
,
4000 EActivity
*activity
;
4001 EAlertSink
*alert_sink
;
4002 GCancellable
*cancellable
;
4003 GFileOutputStream
*output_stream
;
4004 AsyncContext
*async_context
;
4005 GError
*local_error
= NULL
;
4007 async_context
= (AsyncContext
*) user_data
;
4009 activity
= async_context
->activity
;
4010 alert_sink
= e_activity_get_alert_sink (activity
);
4011 cancellable
= e_activity_get_cancellable (activity
);
4013 output_stream
= g_file_replace_finish (
4014 G_FILE (source_object
), result
, &local_error
);
4018 ((output_stream
!= NULL
) && (local_error
== NULL
)) ||
4019 ((output_stream
== NULL
) && (local_error
!= NULL
)));
4021 if (e_activity_handle_cancellation (activity
, local_error
)) {
4022 g_error_free (local_error
);
4023 async_context_free (async_context
);
4025 } else if (local_error
!= NULL
) {
4028 "widgets:no-image-save",
4029 local_error
->message
, NULL
);
4030 g_error_free (local_error
);
4031 async_context_free (async_context
);
4034 g_output_stream_splice_async (
4035 G_OUTPUT_STREAM (output_stream
),
4036 async_context
->input_stream
,
4037 G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE
|
4038 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET
,
4041 web_view_cursor_image_save_splice_cb
,
4045 g_clear_object (&output_stream
);
4048 /* Helper for e_web_view_cursor_image_save() */
4050 web_view_cursor_image_save_request_cb (GObject
*source_object
,
4051 GAsyncResult
*result
,
4054 EActivity
*activity
;
4055 EAlertSink
*alert_sink
;
4056 GCancellable
*cancellable
;
4057 GInputStream
*input_stream
;
4058 AsyncContext
*async_context
;
4059 GError
*local_error
= NULL
;
4061 async_context
= (AsyncContext
*) user_data
;
4063 activity
= async_context
->activity
;
4064 alert_sink
= e_activity_get_alert_sink (activity
);
4065 cancellable
= e_activity_get_cancellable (activity
);
4067 input_stream
= e_web_view_request_finish (
4068 E_WEB_VIEW (source_object
), result
, &local_error
);
4072 ((input_stream
!= NULL
) && (local_error
== NULL
)) ||
4073 ((input_stream
== NULL
) && (local_error
!= NULL
)));
4075 if (e_activity_handle_cancellation (activity
, local_error
)) {
4076 g_error_free (local_error
);
4077 async_context_free (async_context
);
4079 } else if (local_error
!= NULL
) {
4082 "widgets:no-image-save",
4083 local_error
->message
, NULL
);
4084 g_error_free (local_error
);
4085 async_context_free (async_context
);
4088 async_context
->input_stream
= g_object_ref (input_stream
);
4090 /* Open an output stream to the destination file. */
4091 g_file_replace_async (
4092 async_context
->destination
,
4094 G_FILE_CREATE_REPLACE_DESTINATION
,
4097 web_view_cursor_image_save_replace_cb
,
4101 g_clear_object (&input_stream
);
4105 * e_web_view_cursor_image_save:
4106 * @web_view: an #EWebView
4108 * Prompts the user to choose a destination file and then asynchronously
4109 * saves the image under the cursor to the destination file.
4111 * This function triggers a #EWebView::new-activity signal emission so
4112 * the asynchronous operation can be tracked and/or cancelled.
4115 e_web_view_cursor_image_save (EWebView
*web_view
)
4117 GtkFileChooser
*file_chooser
;
4118 GFile
*destination
= NULL
;
4123 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4125 if (web_view
->priv
->cursor_image_src
== NULL
)
4128 toplevel
= gtk_widget_get_toplevel (GTK_WIDGET (web_view
));
4129 toplevel
= gtk_widget_is_toplevel (toplevel
) ? toplevel
: NULL
;
4131 dialog
= gtk_file_chooser_dialog_new (
4132 _("Save Image"), toplevel
,
4133 GTK_FILE_CHOOSER_ACTION_SAVE
,
4134 _("_Cancel"), GTK_RESPONSE_CANCEL
,
4135 _("_Save"), GTK_RESPONSE_ACCEPT
, NULL
);
4137 gtk_dialog_set_default_response (
4138 GTK_DIALOG (dialog
), GTK_RESPONSE_ACCEPT
);
4140 file_chooser
= GTK_FILE_CHOOSER (dialog
);
4141 gtk_file_chooser_set_local_only (file_chooser
, FALSE
);
4142 gtk_file_chooser_set_do_overwrite_confirmation (file_chooser
, TRUE
);
4144 suggestion
= e_web_view_suggest_filename (
4145 web_view
, web_view
->priv
->cursor_image_src
);
4147 if (suggestion
!= NULL
) {
4148 gtk_file_chooser_set_current_name (file_chooser
, suggestion
);
4149 g_free (suggestion
);
4152 e_util_load_file_chooser_folder (file_chooser
);
4154 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
) {
4155 e_util_save_file_chooser_folder (file_chooser
);
4157 destination
= gtk_file_chooser_get_file (file_chooser
);
4160 gtk_widget_destroy (dialog
);
4162 if (destination
!= NULL
) {
4163 EActivity
*activity
;
4164 GCancellable
*cancellable
;
4165 AsyncContext
*async_context
;
4169 activity
= e_web_view_new_activity (web_view
);
4170 cancellable
= e_activity_get_cancellable (activity
);
4172 uri
= g_file_get_uri (destination
);
4173 text
= g_strdup_printf (_("Saving image to “%s”"), uri
);
4174 e_activity_set_text (activity
, text
);
4178 async_context
= g_slice_new0 (AsyncContext
);
4179 async_context
->activity
= g_object_ref (activity
);
4180 async_context
->destination
= g_object_ref (destination
);
4182 e_web_view_request (
4184 web_view
->priv
->cursor_image_src
,
4186 web_view_cursor_image_save_request_cb
,
4189 g_object_unref (activity
);
4190 g_object_unref (destination
);
4194 /* Helper for e_web_view_request() */
4196 web_view_request_process_thread (GTask
*task
,
4197 gpointer source_object
,
4199 GCancellable
*cancellable
)
4201 AsyncContext
*async_context
= task_data
;
4202 gint64 stream_length
= -1;
4203 gchar
*mime_type
= NULL
;
4204 GError
*local_error
= NULL
;
4206 if (!e_content_request_process_sync (async_context
->content_request
,
4207 async_context
->uri
, source_object
, &async_context
->input_stream
,
4208 &stream_length
, &mime_type
, cancellable
, &local_error
)) {
4209 g_task_return_error (task
, local_error
);
4211 g_task_return_boolean (task
, TRUE
);
4218 * e_web_view_request:
4219 * @web_view: an #EWebView
4220 * @uri: the URI to load
4221 * @cancellable: optional #GCancellable object, or %NULL
4222 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
4223 * @user_data: data to pass to the callback function
4225 * Asynchronously requests data at @uri as displaed in the @web_view.
4227 * When the operation is finished, @callback will be called. You can then
4228 * call e_web_view_request_finish() to get the result of the operation.
4231 e_web_view_request (EWebView
*web_view
,
4233 GCancellable
*cancellable
,
4234 GAsyncReadyCallback callback
,
4237 EContentRequest
*content_request
= NULL
;
4238 AsyncContext
*async_context
;
4242 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4243 g_return_if_fail (uri
!= NULL
);
4245 for (link
= web_view
->priv
->content_requests
; link
; link
= g_slist_next (link
)) {
4246 EContentRequest
*adept
= link
->data
;
4248 if (!E_IS_CONTENT_REQUEST (adept
) ||
4249 !e_content_request_can_process_uri (adept
, uri
))
4252 content_request
= adept
;
4256 async_context
= g_slice_new0 (AsyncContext
);
4257 async_context
->uri
= g_strdup (uri
);
4259 task
= g_task_new (web_view
, cancellable
, callback
, user_data
);
4260 g_task_set_task_data (task
, async_context
, async_context_free
);
4261 g_task_set_check_cancellable (task
, TRUE
);
4263 if (content_request
) {
4264 async_context
->content_request
= g_object_ref (content_request
);
4265 g_task_run_in_thread (task
, web_view_request_process_thread
);
4267 g_task_return_new_error (task
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
4268 _("Cannot get URI “%s”, do not know how to download it."), uri
);
4271 g_object_unref (task
);
4275 * e_web_view_request_finish:
4276 * @web_view: an #EWebView
4277 * @result: a #GAsyncResult
4278 * @error: return location for a #GError, or %NULL
4280 * Finishes the operation started with e_web_view_request().
4282 * Unreference the returned #GInputStream with g_object_unref() when finished
4283 * with it. If an error occurred, the function will set @error and return
4286 * Returns: a #GInputStream, or %NULL
4289 e_web_view_request_finish (EWebView
*web_view
,
4290 GAsyncResult
*result
,
4293 AsyncContext
*async_context
;
4295 g_return_val_if_fail (g_task_is_valid (result
, web_view
), NULL
);
4297 if (!g_task_propagate_boolean (G_TASK (result
), error
))
4300 async_context
= g_task_get_task_data (G_TASK (result
));
4302 g_return_val_if_fail (async_context
->input_stream
!= NULL
, NULL
);
4304 return g_object_ref (async_context
->input_stream
);
4308 * e_web_view_create_and_add_css_style_sheet:
4309 * @web_view: an #EWebView
4310 * @style_sheet_id: CSS style sheet's id
4312 * Creates new CSS style sheet with given @style_sheel_id and inserts
4313 * it into given @web_view document.
4316 e_web_view_create_and_add_css_style_sheet (EWebView
*web_view
,
4317 const gchar
*style_sheet_id
)
4319 GDBusProxy
*web_extension
;
4321 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4322 g_return_if_fail (style_sheet_id
&& *style_sheet_id
);
4324 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4325 if (web_extension
) {
4326 e_util_invoke_g_dbus_proxy_call_with_error_check (
4328 "CreateAndAddCSSStyleSheet",
4331 webkit_web_view_get_page_id (
4332 WEBKIT_WEB_VIEW (web_view
)),
4339 * e_web_view_add_css_rule_into_style_sheet:
4340 * @web_view: an #EWebView
4341 * @style_sheet_id: CSS style sheet's id
4342 * @selector: CSS selector
4343 * @style: style for given selector
4345 * Insert new CSS rule (defined with @selector and @style) into CSS style sheet
4346 * with given @style_sheet_id. If style sheet doesn't exist, it's created.
4348 * The rule is inserted to every DOM document that is in page. That means also
4349 * into DOM documents inside iframe elements.
4352 e_web_view_add_css_rule_into_style_sheet (EWebView
*web_view
,
4353 const gchar
*style_sheet_id
,
4354 const gchar
*selector
,
4357 GDBusProxy
*web_extension
;
4359 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4360 g_return_if_fail (style_sheet_id
&& *style_sheet_id
);
4361 g_return_if_fail (selector
&& *selector
);
4362 g_return_if_fail (style
&& *style
);
4364 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4365 if (web_extension
) {
4366 e_util_invoke_g_dbus_proxy_call_with_error_check (
4368 "AddCSSRuleIntoStyleSheet",
4371 webkit_web_view_get_page_id (
4372 WEBKIT_WEB_VIEW (web_view
)),
4381 * e_web_view_get_document_uri_from_point:
4382 * @web_view: an #EWebView
4386 * Returns: A document URI which is under the @x, @y coordinates or %NULL,
4387 * if there is none. Free the returned pointer with g_free() when done with it.
4392 e_web_view_get_document_uri_from_point (EWebView
*web_view
,
4396 GDBusProxy
*web_extension
;
4398 GError
*local_error
= NULL
;
4400 g_return_val_if_fail (E_IS_WEB_VIEW (web_view
), NULL
);
4402 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4406 result
= e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
4408 "GetDocumentURIFromPoint",
4411 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
4414 G_DBUS_CALL_FLAGS_NONE
,
4420 g_dbus_error_strip_remote_error (local_error
);
4422 e_util_claim_dbus_proxy_call_error (web_extension
, "GetDocumentURIFromPoint", local_error
);
4423 g_clear_error (&local_error
);
4428 g_variant_get (result
, "(s)", &uri
);
4429 g_variant_unref (result
);
4431 if (g_strcmp0 (uri
, "") == 0) {
4443 * e_web_view_set_document_iframe_src:
4444 * @web_view: an #EWebView
4445 * @document_uri: a document URI for whose IFrame change the source
4446 * @new_iframe_src: the source to change the IFrame to
4448 * Change IFrame source for the given @document_uri IFrame
4449 * to the @new_iframe_src.
4454 e_web_view_set_document_iframe_src (EWebView
*web_view
,
4455 const gchar
*document_uri
,
4456 const gchar
*new_iframe_src
)
4458 GDBusProxy
*web_extension
;
4460 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4462 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4466 /* Cannot call this synchronously, blocking the local main loop, because the reload
4467 can on the WebProcess side can be asking for a redirection policy, waiting
4468 for a response which may be waiting in the blocked main loop. */
4469 e_util_invoke_g_dbus_proxy_call_with_error_check (
4471 "SetDocumentIFrameSrc",
4474 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
4481 * EWebViewElementClickedFunc:
4482 * @web_view: an #EWebView
4483 * @element_class: an element class, as set on the element which had been clicked
4484 * @element_value: a 'value' attribute content of the clicked element
4485 * @element_position: a #GtkAllocation with the position of the clicked element
4486 * @user_data: user data as provided in the e_web_view_register_element_clicked() call
4488 * The callback is called whenever an element of class @element_class is clicked.
4489 * The @element_value is a content of the 'value' attribute of the clicked element.
4490 * The @element_position is the place of the element within the web page, already
4491 * accounting scrollbar positions.
4493 * See: e_web_view_register_element_clicked, e_web_view_unregister_element_clicked
4499 * e_web_view_register_element_clicked:
4500 * @web_view: an #EWebView
4501 * @element_class: an element class on which to listen for clicking
4502 * @callback: an #EWebViewElementClickedFunc to call, when the element is clicked
4503 * @user_data: user data to pass to @callback
4505 * Registers a @callback to be called when any element of the class @element_class
4506 * is clicked. If the element contains a 'value' attribute, then it is passed to
4507 * the @callback too. These callback are valid until a new content of the @web_view
4508 * is loaded, after which all the registered callbacks are forgotten.
4513 e_web_view_register_element_clicked (EWebView
*web_view
,
4514 const gchar
*element_class
,
4515 EWebViewElementClickedFunc callback
,
4518 ElementClickedData
*ecd
;
4522 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4523 g_return_if_fail (element_class
!= NULL
);
4524 g_return_if_fail (callback
!= NULL
);
4526 cbs
= g_hash_table_lookup (web_view
->priv
->element_clicked_cbs
, element_class
);
4528 for (ii
= 0; ii
< cbs
->len
; ii
++) {
4529 ecd
= g_ptr_array_index (cbs
, ii
);
4531 if (ecd
&& ecd
->callback
== callback
&& ecd
->user_data
== user_data
) {
4532 /* Callback is already registered, but re-register it, in case the page
4533 was changed dynamically and new elements with the given call are added. */
4534 web_view_register_element_clicked_hfunc ((gpointer
) element_class
, cbs
, web_view
);
4540 ecd
= g_new0 (ElementClickedData
, 1);
4541 ecd
->callback
= callback
;
4542 ecd
->user_data
= user_data
;
4545 cbs
= g_ptr_array_new_full (1, g_free
);
4546 g_ptr_array_add (cbs
, ecd
);
4548 g_hash_table_insert (web_view
->priv
->element_clicked_cbs
, g_strdup (element_class
), cbs
);
4550 g_ptr_array_add (cbs
, ecd
);
4553 /* Dynamically changing page can call this multiple times; re-register all classes */
4554 g_hash_table_foreach (web_view
->priv
->element_clicked_cbs
, web_view_register_element_clicked_hfunc
, web_view
);
4558 * e_web_view_unregister_element_clicked:
4559 * @web_view: an #EWebView
4560 * @element_class: an element class on which to listen for clicking
4561 * @callback: an #EWebViewElementClickedFunc to call, when the element is clicked
4562 * @user_data: user data to pass to @callback
4564 * Unregisters the @callback for the @element_class with the given @user_data, which
4565 * should be previously registered with e_web_view_register_element_clicked(). This
4566 * unregister is usually not needed, because the @web_view unregisters all callbacks
4567 * when a new content is loaded.
4572 e_web_view_unregister_element_clicked (EWebView
*web_view
,
4573 const gchar
*element_class
,
4574 EWebViewElementClickedFunc callback
,
4577 ElementClickedData
*ecd
;
4581 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4582 g_return_if_fail (element_class
!= NULL
);
4583 g_return_if_fail (callback
!= NULL
);
4585 cbs
= g_hash_table_lookup (web_view
->priv
->element_clicked_cbs
, element_class
);
4589 for (ii
= 0; ii
< cbs
->len
; ii
++) {
4590 ecd
= g_ptr_array_index (cbs
, ii
);
4592 if (ecd
&& ecd
->callback
== callback
&& ecd
->user_data
== user_data
) {
4593 g_ptr_array_remove (cbs
, ecd
);
4595 g_hash_table_remove (web_view
->priv
->element_clicked_cbs
, element_class
);
4602 e_web_view_set_element_hidden (EWebView
*web_view
,
4603 const gchar
*element_id
,
4606 GDBusProxy
*web_extension
;
4608 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4609 g_return_if_fail (element_id
&& *element_id
);
4611 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4615 e_util_invoke_g_dbus_proxy_call_with_error_check (
4620 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
4627 e_web_view_set_element_style_property (EWebView
*web_view
,
4628 const gchar
*element_id
,
4629 const gchar
*property_name
,
4631 const gchar
*priority
)
4633 GDBusProxy
*web_extension
;
4635 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4636 g_return_if_fail (element_id
&& *element_id
);
4637 g_return_if_fail (property_name
&& *property_name
);
4639 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4643 e_util_invoke_g_dbus_proxy_call_with_error_check (
4645 "SetElementStyleProperty",
4648 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
4652 priority
? priority
: ""),
4657 e_web_view_set_element_attribute (EWebView
*web_view
,
4658 const gchar
*element_id
,
4659 const gchar
*namespace_uri
,
4660 const gchar
*qualified_name
,
4663 GDBusProxy
*web_extension
;
4665 g_return_if_fail (E_IS_WEB_VIEW (web_view
));
4666 g_return_if_fail (element_id
&& *element_id
);
4667 g_return_if_fail (qualified_name
&& *qualified_name
);
4669 web_extension
= e_web_view_get_web_extension_proxy (web_view
);
4673 e_util_invoke_g_dbus_proxy_call_with_error_check (
4675 "SetElementAttribute",
4678 webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view
)),
4680 namespace_uri
? namespace_uri
: "",
4682 value
? value
: ""),