No issues found
1 /*
2 * e-web-view.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "e-web-view.h"
24
25 #include <math.h>
26
27 #include <string.h>
28 #include <glib/gi18n-lib.h>
29 #include <pango/pango.h>
30
31 #include <camel/camel.h>
32 #include <libebackend/libebackend.h>
33
34 #include <e-util/e-util.h>
35 #include <libevolution-utils/e-alert-dialog.h>
36 #include <libevolution-utils/e-alert-sink.h>
37 #include <e-util/e-plugin-ui.h>
38 #include <e-util/e-file-request.h>
39 #include <e-util/e-stock-request.h>
40
41 #define LIBSOUP_USE_UNSTABLE_REQUEST_API
42 #include <libsoup/soup.h>
43 #include <libsoup/soup-requester.h>
44
45 #include "e-popup-action.h"
46 #include "e-selectable.h"
47 #include <stdlib.h>
48
49 #define E_WEB_VIEW_GET_PRIVATE(obj) \
50 (G_TYPE_INSTANCE_GET_PRIVATE \
51 ((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
52
53 typedef struct _EWebViewRequest EWebViewRequest;
54
55 struct _EWebViewPrivate {
56 GList *requests;
57 GtkUIManager *ui_manager;
58 gchar *selected_uri;
59 GdkPixbufAnimation *cursor_image;
60 gchar *cursor_image_src;
61
62 GSList *highlights;
63
64 GtkAction *open_proxy;
65 GtkAction *print_proxy;
66 GtkAction *save_as_proxy;
67
68 /* Lockdown Options */
69 guint disable_printing : 1;
70 guint disable_save_to_disk : 1;
71
72 guint caret_mode : 1;
73
74 GSettings *font_settings;
75 GSettings *aliasing_settings;
76 };
77
78 enum {
79 PROP_0,
80 PROP_CARET_MODE,
81 PROP_COPY_TARGET_LIST,
82 PROP_CURSOR_IMAGE,
83 PROP_CURSOR_IMAGE_SRC,
84 PROP_DISABLE_PRINTING,
85 PROP_DISABLE_SAVE_TO_DISK,
86 PROP_INLINE_SPELLING,
87 PROP_MAGIC_LINKS,
88 PROP_MAGIC_SMILEYS,
89 PROP_OPEN_PROXY,
90 PROP_PRINT_PROXY,
91 PROP_SAVE_AS_PROXY,
92 PROP_SELECTED_URI
93 };
94
95 enum {
96 POPUP_EVENT,
97 STATUS_MESSAGE,
98 STOP_LOADING,
99 UPDATE_ACTIONS,
100 PROCESS_MAILTO,
101 LAST_SIGNAL
102 };
103
104 static guint signals[LAST_SIGNAL];
105
106 static const gchar *ui =
107 "<ui>"
108 " <popup name='context'>"
109 " <menuitem action='copy-clipboard'/>"
110 " <separator/>"
111 " <placeholder name='custom-actions-1'>"
112 " <menuitem action='open'/>"
113 " <menuitem action='save-as'/>"
114 " <menuitem action='http-open'/>"
115 " <menuitem action='send-message'/>"
116 " <menuitem action='print'/>"
117 " </placeholder>"
118 " <placeholder name='custom-actions-2'>"
119 " <menuitem action='uri-copy'/>"
120 " <menuitem action='mailto-copy'/>"
121 " <menuitem action='image-copy'/>"
122 " </placeholder>"
123 " <placeholder name='custom-actions-3'/>"
124 " <separator/>"
125 " <menuitem action='select-all'/>"
126 " <placeholder name='inspect-menu' />"
127 " </popup>"
128 "</ui>";
129
130 /* Forward Declarations */
131 static void e_web_view_alert_sink_init (EAlertSinkInterface *interface);
132 static void e_web_view_selectable_init (ESelectableInterface *interface);
133
134 G_DEFINE_TYPE_WITH_CODE (
135 EWebView,
136 e_web_view,
137 WEBKIT_TYPE_WEB_VIEW,
138 G_IMPLEMENT_INTERFACE (
139 E_TYPE_EXTENSIBLE, NULL)
140 G_IMPLEMENT_INTERFACE (
141 E_TYPE_ALERT_SINK,
142 e_web_view_alert_sink_init)
143 G_IMPLEMENT_INTERFACE (
144 E_TYPE_SELECTABLE,
145 e_web_view_selectable_init))
146
147 static void
148 action_copy_clipboard_cb (GtkAction *action,
149 EWebView *web_view)
150 {
151 e_web_view_copy_clipboard (web_view);
152 }
153
154 static void
155 action_http_open_cb (GtkAction *action,
156 EWebView *web_view)
157 {
158 const gchar *uri;
159 gpointer parent;
160
161 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
162 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
163
164 uri = e_web_view_get_selected_uri (web_view);
165 g_return_if_fail (uri != NULL);
166
167 e_show_uri (parent, uri);
168 }
169
170 static void
171 action_mailto_copy_cb (GtkAction *action,
172 EWebView *web_view)
173 {
174 CamelURL *curl;
175 CamelInternetAddress *inet_addr;
176 GtkClipboard *clipboard;
177 const gchar *uri;
178 gchar *text;
179
180 uri = e_web_view_get_selected_uri (web_view);
181 g_return_if_fail (uri != NULL);
182
183 /* This should work because we checked it in update_actions(). */
184 curl = camel_url_new (uri, NULL);
185 g_return_if_fail (curl != NULL);
186
187 inet_addr = camel_internet_address_new ();
188 camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path);
189 text = camel_address_format (CAMEL_ADDRESS (inet_addr));
190 if (text == NULL || *text == '\0')
191 text = g_strdup (uri + strlen ("mailto:"));
192
193 g_object_unref (inet_addr);
194 camel_url_free (curl);
195
196 clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
197 gtk_clipboard_set_text (clipboard, text, -1);
198 gtk_clipboard_store (clipboard);
199
200 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
201 gtk_clipboard_set_text (clipboard, text, -1);
202 gtk_clipboard_store (clipboard);
203
204 g_free (text);
205 }
206
207 static void
208 action_select_all_cb (GtkAction *action,
209 EWebView *web_view)
210 {
211 e_web_view_select_all (web_view);
212 }
213
214 static void
215 action_send_message_cb (GtkAction *action,
216 EWebView *web_view)
217 {
218 const gchar *uri;
219 gpointer parent;
220 gboolean handled;
221
222 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
223 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
224
225 uri = e_web_view_get_selected_uri (web_view);
226 g_return_if_fail (uri != NULL);
227
228 handled = FALSE;
229 g_signal_emit (web_view, signals[PROCESS_MAILTO], 0, uri, &handled);
230
231 if (!handled)
232 e_show_uri (parent, uri);
233 }
234
235 static void
236 action_uri_copy_cb (GtkAction *action,
237 EWebView *web_view)
238 {
239 GtkClipboard *clipboard;
240 const gchar *uri;
241
242 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
243 uri = e_web_view_get_selected_uri (web_view);
244 g_return_if_fail (uri != NULL);
245
246 gtk_clipboard_set_text (clipboard, uri, -1);
247 gtk_clipboard_store (clipboard);
248 }
249
250 static void
251 action_image_copy_cb (GtkAction *action,
252 EWebView *web_view)
253 {
254 GtkClipboard *clipboard;
255 GdkPixbufAnimation *animation;
256 GdkPixbuf *pixbuf;
257
258 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
259 animation = e_web_view_get_cursor_image (web_view);
260 g_return_if_fail (animation != NULL);
261
262 pixbuf = gdk_pixbuf_animation_get_static_image (animation);
263 if (pixbuf == NULL)
264 return;
265
266 gtk_clipboard_set_image (clipboard, pixbuf);
267 gtk_clipboard_store (clipboard);
268 }
269
270 static GtkActionEntry uri_entries[] = {
271
272 { "uri-copy",
273 GTK_STOCK_COPY,
274 N_("_Copy Link Location"),
275 NULL,
276 N_("Copy the link to the clipboard"),
277 G_CALLBACK (action_uri_copy_cb) }
278 };
279
280 static GtkActionEntry http_entries[] = {
281
282 { "http-open",
283 "emblem-web",
284 N_("_Open Link in Browser"),
285 NULL,
286 N_("Open the link in a web browser"),
287 G_CALLBACK (action_http_open_cb) }
288 };
289
290 static GtkActionEntry mailto_entries[] = {
291
292 { "mailto-copy",
293 GTK_STOCK_COPY,
294 N_("_Copy Email Address"),
295 NULL,
296 N_("Copy the email address to the clipboard"),
297 G_CALLBACK (action_mailto_copy_cb) },
298
299 { "send-message",
300 "mail-message-new",
301 N_("_Send New Message To..."),
302 NULL,
303 N_("Send a mail message to this address"),
304 G_CALLBACK (action_send_message_cb) }
305 };
306
307 static GtkActionEntry image_entries[] = {
308
309 { "image-copy",
310 GTK_STOCK_COPY,
311 N_("_Copy Image"),
312 NULL,
313 N_("Copy the image to the clipboard"),
314 G_CALLBACK (action_image_copy_cb) }
315 };
316
317 static GtkActionEntry selection_entries[] = {
318
319 { "copy-clipboard",
320 GTK_STOCK_COPY,
321 NULL,
322 NULL,
323 N_("Copy the selection"),
324 G_CALLBACK (action_copy_clipboard_cb) },
325 };
326
327 static GtkActionEntry standard_entries[] = {
328
329 { "select-all",
330 GTK_STOCK_SELECT_ALL,
331 NULL,
332 NULL,
333 N_("Select all text and images"),
334 G_CALLBACK (action_select_all_cb) }
335 };
336
337 static void
338 web_view_menu_item_select_cb (EWebView *web_view,
339 GtkWidget *widget)
340 {
341 GtkAction *action;
342 GtkActivatable *activatable;
343 const gchar *tooltip;
344
345 activatable = GTK_ACTIVATABLE (widget);
346 action = gtk_activatable_get_related_action (activatable);
347 tooltip = gtk_action_get_tooltip (action);
348
349 if (tooltip == NULL)
350 return;
351
352 e_web_view_status_message (web_view, tooltip);
353 }
354
355 static void
356 replace_text (WebKitDOMNode *node,
357 const gchar *text,
358 WebKitDOMNode *replacement)
359 {
360 /* NodeType 3 = TEXT_NODE */
361 if (webkit_dom_node_get_node_type (node) == 3) {
362 gint text_length = strlen (text);
363
364 while (node) {
365
366 WebKitDOMNode *current_node, *replacement_node;
367 const gchar *node_data, *offset;
368 goffset split_offset;
369 gint data_length;
370
371 current_node = node;
372
373 /* Don't use the WEBKIT_DOM_CHARACTER_DATA macro for
374 * casting. WebKit lies about type of the object and
375 * GLib will throw runtime warning about node not being
376 * WebKitDOMCharacterData, but the function will return
377 * correct and valid data.
378 * IMO it's bug in the Gtk bindings and WebKit internally
379 * handles it by the nodeType so therefor it works
380 * event for "invalid" objects. But really, who knows..?
381 */
382 node_data = webkit_dom_character_data_get_data (
383 (WebKitDOMCharacterData *) node);
384
385 offset = strstr (node_data, text);
386 if (offset == NULL) {
387 node = NULL;
388 continue;
389 }
390
391 split_offset = offset - node_data + text_length;
392 replacement_node =
393 webkit_dom_node_clone_node (replacement, TRUE);
394
395 data_length = webkit_dom_character_data_get_length (
396 (WebKitDOMCharacterData *) node);
397 if (split_offset < data_length) {
398
399 WebKitDOMNode *parent_node;
400
401 node = WEBKIT_DOM_NODE (
402 webkit_dom_text_split_text (
403 (WebKitDOMText *) node,
404 offset - node_data + text_length,
405 NULL));
406 parent_node = webkit_dom_node_get_parent_node (node);
407 webkit_dom_node_insert_before (
408 parent_node, replacement_node,
409 node, NULL);
410
411 } else {
412 WebKitDOMNode *parent_node;
413
414 parent_node = webkit_dom_node_get_parent_node (node);
415 webkit_dom_node_append_child (
416 parent_node,
417 replacement_node, NULL);
418 }
419
420 webkit_dom_character_data_delete_data (
421 (WebKitDOMCharacterData *) (current_node),
422 offset - node_data, text_length, NULL);
423 }
424
425 } else {
426 WebKitDOMNode *child, *next_child;
427
428 /* Iframe? Let's traverse inside! */
429 if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) {
430
431 WebKitDOMDocument *frame_document;
432
433 frame_document =
434 webkit_dom_html_iframe_element_get_content_document (
435 WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
436 replace_text (
437 WEBKIT_DOM_NODE (frame_document),
438 text, replacement);
439
440 } else {
441 child = webkit_dom_node_get_first_child (node);
442 while (child != NULL) {
443 next_child = webkit_dom_node_get_next_sibling (child);
444 replace_text (child, text, replacement);
445 child = next_child;
446 }
447 }
448 }
449 }
450
451 static void
452 web_view_update_document_highlights (EWebView *web_view)
453 {
454 WebKitDOMDocument *document;
455 GSList *iter;
456
457 document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
458
459 for (iter = web_view->priv->highlights; iter; iter = iter->next) {
460
461 WebKitDOMDocumentFragment *frag;
462 WebKitDOMElement *span;
463
464 span = webkit_dom_document_create_element (document, "span", NULL);
465
466 /* See https://bugzilla.gnome.org/show_bug.cgi?id=681400
467 * FIXME: This can be removed once we require WebKitGtk 1.10+ */
468 #if WEBKIT_CHECK_VERSION (1, 9, 6)
469 webkit_dom_element_set_class_name (
470 span, "__evo-highlight");
471 #else
472 webkit_dom_html_element_set_class_name (
473 WEBKIT_DOM_HTML_ELEMENT (span), "__evo-highlight");
474 #endif
475
476 webkit_dom_html_element_set_inner_text (
477 WEBKIT_DOM_HTML_ELEMENT (span), iter->data, NULL);
478
479 frag = webkit_dom_document_create_document_fragment (document);
480 webkit_dom_node_append_child (
481 WEBKIT_DOM_NODE (frag), WEBKIT_DOM_NODE (span), NULL);
482
483 replace_text (
484 WEBKIT_DOM_NODE (document),
485 iter->data, WEBKIT_DOM_NODE (frag));
486 }
487 }
488
489 static void
490 web_view_menu_item_deselect_cb (EWebView *web_view)
491 {
492 e_web_view_status_message (web_view, NULL);
493 }
494
495 static void
496 web_view_connect_proxy_cb (EWebView *web_view,
497 GtkAction *action,
498 GtkWidget *proxy)
499 {
500 if (!GTK_IS_MENU_ITEM (proxy))
501 return;
502
503 g_signal_connect_swapped (
504 proxy, "select",
505 G_CALLBACK (web_view_menu_item_select_cb), web_view);
506
507 g_signal_connect_swapped (
508 proxy, "deselect",
509 G_CALLBACK (web_view_menu_item_deselect_cb), web_view);
510 }
511
512 static GtkWidget *
513 web_view_create_plugin_widget_cb (EWebView *web_view,
514 const gchar *mime_type,
515 const gchar *uri,
516 GHashTable *param)
517 {
518 EWebViewClass *class;
519
520 /* XXX WebKitWebView does not provide a class method for
521 * this signal, so we do so we can override the default
522 * behavior from subclasses for special URI types. */
523
524 class = E_WEB_VIEW_GET_CLASS (web_view);
525 g_return_val_if_fail (class->create_plugin_widget != NULL, NULL);
526
527 return class->create_plugin_widget (web_view, mime_type, uri, param);
528 }
529
530 static void
531 web_view_hovering_over_link_cb (EWebView *web_view,
532 const gchar *title,
533 const gchar *uri)
534 {
535 EWebViewClass *class;
536
537 /* XXX WebKitWebView does not provide a class method for
538 * this signal, so we do so we can override the default
539 * behavior from subclasses for special URI types. */
540
541 class = E_WEB_VIEW_GET_CLASS (web_view);
542 g_return_if_fail (class->hovering_over_link != NULL);
543
544 class->hovering_over_link (web_view, title, uri);
545 }
546
547 static gboolean
548 web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
549 WebKitWebFrame *frame,
550 WebKitNetworkRequest *request,
551 WebKitWebNavigationAction *navigation_action,
552 WebKitWebPolicyDecision *policy_decision)
553 {
554 EWebViewClass *class;
555 WebKitWebNavigationReason reason;
556 const gchar *uri;
557
558 reason = webkit_web_navigation_action_get_reason (navigation_action);
559 if (reason != WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
560 return FALSE;
561
562 /* XXX WebKitWebView does not provide a class method for
563 * this signal, so we do so we can override the default
564 * behavior from subclasses for special URI types. */
565
566 class = E_WEB_VIEW_GET_CLASS (web_view);
567 g_return_val_if_fail (class->link_clicked != NULL, FALSE);
568
569 webkit_web_policy_decision_ignore (policy_decision);
570
571 uri = webkit_network_request_get_uri (request);
572
573 class->link_clicked (web_view, uri);
574
575 return TRUE;
576 }
577
578 static void
579 web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
580 GParamSpec *pspec,
581 gpointer user_data)
582 {
583 WebKitLoadStatus status;
584 EWebView *web_view;
585
586 status = webkit_web_view_get_load_status (webkit_web_view);
587 if (status != WEBKIT_LOAD_FINISHED)
588 return;
589
590 web_view = E_WEB_VIEW (webkit_web_view);
591 web_view_update_document_highlights (web_view);
592
593 /* Workaround webkit bug https://bugs.webkit.org/show_bug.cgi?id=89553 */
594 e_web_view_zoom_in (web_view);
595 e_web_view_zoom_out (web_view);
596 }
597
598 static void
599 web_view_set_property (GObject *object,
600 guint property_id,
601 const GValue *value,
602 GParamSpec *pspec)
603 {
604 switch (property_id) {
605 case PROP_CARET_MODE:
606 e_web_view_set_caret_mode (
607 E_WEB_VIEW (object),
608 g_value_get_boolean (value));
609 return;
610
611 case PROP_CURSOR_IMAGE:
612 e_web_view_set_cursor_image (
613 E_WEB_VIEW (object),
614 g_value_get_object (value));
615 return;
616
617 case PROP_CURSOR_IMAGE_SRC:
618 e_web_view_set_cursor_image_src (
619 E_WEB_VIEW (object),
620 g_value_get_string (value));
621 return;
622
623 case PROP_DISABLE_PRINTING:
624 e_web_view_set_disable_printing (
625 E_WEB_VIEW (object),
626 g_value_get_boolean (value));
627 return;
628
629 case PROP_DISABLE_SAVE_TO_DISK:
630 e_web_view_set_disable_save_to_disk (
631 E_WEB_VIEW (object),
632 g_value_get_boolean (value));
633 return;
634
635 case PROP_INLINE_SPELLING:
636 e_web_view_set_inline_spelling (
637 E_WEB_VIEW (object),
638 g_value_get_boolean (value));
639 return;
640
641 case PROP_MAGIC_LINKS:
642 e_web_view_set_magic_links (
643 E_WEB_VIEW (object),
644 g_value_get_boolean (value));
645 return;
646
647 case PROP_MAGIC_SMILEYS:
648 e_web_view_set_magic_smileys (
649 E_WEB_VIEW (object),
650 g_value_get_boolean (value));
651 return;
652
653 case PROP_OPEN_PROXY:
654 e_web_view_set_open_proxy (
655 E_WEB_VIEW (object),
656 g_value_get_object (value));
657 return;
658
659 case PROP_PRINT_PROXY:
660 e_web_view_set_print_proxy (
661 E_WEB_VIEW (object),
662 g_value_get_object (value));
663 return;
664
665 case PROP_SAVE_AS_PROXY:
666 e_web_view_set_save_as_proxy (
667 E_WEB_VIEW (object),
668 g_value_get_object (value));
669 return;
670
671 case PROP_SELECTED_URI:
672 e_web_view_set_selected_uri (
673 E_WEB_VIEW (object),
674 g_value_get_string (value));
675 return;
676 }
677 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
678 }
679
680 static void
681 web_view_get_property (GObject *object,
682 guint property_id,
683 GValue *value,
684 GParamSpec *pspec)
685 {
686 switch (property_id) {
687 case PROP_CARET_MODE:
688 g_value_set_boolean (
689 value, e_web_view_get_caret_mode (
690 E_WEB_VIEW (object)));
691 return;
692
693 case PROP_CURSOR_IMAGE:
694 g_value_set_object (
695 value, e_web_view_get_cursor_image (
696 E_WEB_VIEW (object)));
697 return;
698
699 case PROP_CURSOR_IMAGE_SRC:
700 g_value_set_string (
701 value, e_web_view_get_cursor_image_src (
702 E_WEB_VIEW (object)));
703 return;
704
705 case PROP_DISABLE_PRINTING:
706 g_value_set_boolean (
707 value, e_web_view_get_disable_printing (
708 E_WEB_VIEW (object)));
709 return;
710
711 case PROP_DISABLE_SAVE_TO_DISK:
712 g_value_set_boolean (
713 value, e_web_view_get_disable_save_to_disk (
714 E_WEB_VIEW (object)));
715 return;
716
717 case PROP_INLINE_SPELLING:
718 g_value_set_boolean (
719 value, e_web_view_get_inline_spelling (
720 E_WEB_VIEW (object)));
721 return;
722
723 case PROP_MAGIC_LINKS:
724 g_value_set_boolean (
725 value, e_web_view_get_magic_links (
726 E_WEB_VIEW (object)));
727 return;
728
729 case PROP_MAGIC_SMILEYS:
730 g_value_set_boolean (
731 value, e_web_view_get_magic_smileys (
732 E_WEB_VIEW (object)));
733 return;
734
735 case PROP_OPEN_PROXY:
736 g_value_set_object (
737 value, e_web_view_get_open_proxy (
738 E_WEB_VIEW (object)));
739 return;
740
741 case PROP_PRINT_PROXY:
742 g_value_set_object (
743 value, e_web_view_get_print_proxy (
744 E_WEB_VIEW (object)));
745 return;
746
747 case PROP_SAVE_AS_PROXY:
748 g_value_set_object (
749 value, e_web_view_get_save_as_proxy (
750 E_WEB_VIEW (object)));
751 return;
752
753 case PROP_SELECTED_URI:
754 g_value_set_string (
755 value, e_web_view_get_selected_uri (
756 E_WEB_VIEW (object)));
757 return;
758
759 }
760
761 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
762 }
763
764 static void
765 web_view_dispose (GObject *object)
766 {
767 EWebViewPrivate *priv;
768
769 priv = E_WEB_VIEW_GET_PRIVATE (object);
770
771 if (priv->ui_manager != NULL) {
772 g_object_unref (priv->ui_manager);
773 priv->ui_manager = NULL;
774 }
775
776 if (priv->open_proxy != NULL) {
777 g_object_unref (priv->open_proxy);
778 priv->open_proxy = NULL;
779 }
780
781 if (priv->print_proxy != NULL) {
782 g_object_unref (priv->print_proxy);
783 priv->print_proxy = NULL;
784 }
785
786 if (priv->save_as_proxy != NULL) {
787 g_object_unref (priv->save_as_proxy);
788 priv->save_as_proxy = NULL;
789 }
790
791 if (priv->cursor_image != NULL) {
792 g_object_unref (priv->cursor_image);
793 priv->cursor_image = NULL;
794 }
795
796 if (priv->cursor_image_src != NULL) {
797 g_free (priv->cursor_image_src);
798 priv->cursor_image_src = NULL;
799 }
800
801 if (priv->highlights != NULL) {
802 g_slist_free_full (priv->highlights, g_free);
803 priv->highlights = NULL;
804 }
805
806 if (priv->aliasing_settings != NULL) {
807 g_signal_handlers_disconnect_matched (
808 priv->aliasing_settings, G_SIGNAL_MATCH_DATA,
809 0, 0, NULL, NULL, object);
810 g_object_unref (priv->aliasing_settings);
811 priv->aliasing_settings = NULL;
812 }
813
814 if (priv->font_settings != NULL) {
815 g_signal_handlers_disconnect_matched (
816 priv->font_settings, G_SIGNAL_MATCH_DATA,
817 0, 0, NULL, NULL, object);
818 g_object_unref (priv->font_settings);
819 priv->font_settings = NULL;
820 }
821
822 /* Chain up to parent's dispose() method. */
823 G_OBJECT_CLASS (e_web_view_parent_class)->dispose (object);
824 }
825
826 static void
827 web_view_finalize (GObject *object)
828 {
829 EWebViewPrivate *priv;
830
831 priv = E_WEB_VIEW_GET_PRIVATE (object);
832
833 /* All URI requests should be complete or cancelled by now. */
834 if (priv->requests != NULL)
835 g_warning ("Finalizing EWebView with active URI requests");
836
837 g_free (priv->selected_uri);
838
839 /* Chain up to parent's finalize() method. */
840 G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
841 }
842
843 static void
844 web_view_constructed (GObject *object)
845 {
846 #ifndef G_OS_WIN32
847 GSettings *settings;
848
849 settings = g_settings_new ("org.gnome.desktop.lockdown");
850
851 g_settings_bind (
852 settings, "disable-printing",
853 object, "disable-printing",
854 G_SETTINGS_BIND_GET);
855
856 g_settings_bind (
857 settings, "disable-save-to-disk",
858 object, "disable-save-to-disk",
859 G_SETTINGS_BIND_GET);
860
861 g_object_unref (settings);
862 #endif
863
864 e_extensible_load_extensions (E_EXTENSIBLE (object));
865
866 /* Chain up to parent's constructed() method. */
867 G_OBJECT_CLASS (e_web_view_parent_class)->constructed (object);
868 }
869
870 static gboolean
871 web_view_button_press_event (GtkWidget *widget,
872 GdkEventButton *event)
873 {
874 GtkWidgetClass *widget_class;
875 EWebView *web_view;
876 gboolean event_handled = FALSE;
877 gchar *uri;
878
879 web_view = E_WEB_VIEW (widget);
880
881 if (event != NULL) {
882 WebKitHitTestResult *test;
883 WebKitHitTestResultContext context;
884
885 if (web_view->priv->cursor_image != NULL) {
886 g_object_unref (web_view->priv->cursor_image);
887 web_view->priv->cursor_image = NULL;
888 }
889
890 if (web_view->priv->cursor_image_src != NULL) {
891 g_free (web_view->priv->cursor_image_src);
892 web_view->priv->cursor_image_src = NULL;
893 }
894
895 test = webkit_web_view_get_hit_test_result (
896 WEBKIT_WEB_VIEW (web_view), event);
897 if (test == NULL)
898 goto chainup;
899
900 g_object_get (G_OBJECT (test), "context", &context, NULL);
901
902 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
903 WebKitWebDataSource *data_source;
904 WebKitWebFrame *frame;
905 GList *subresources, *res;
906
907 g_object_get (
908 G_OBJECT (test), "image-uri", &uri, NULL);
909
910 if (uri == NULL)
911 goto chainup;
912
913 g_free (web_view->priv->cursor_image_src);
914 web_view->priv->cursor_image_src = uri;
915
916 /* Iterate through all resources of the loaded webpage and
917 * try to find resource with URI matching cursor_image_src */
918 frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
919 data_source = webkit_web_frame_get_data_source (frame);
920 subresources = webkit_web_data_source_get_subresources (data_source);
921 for (res = subresources; res; res = res->next) {
922 WebKitWebResource *src = res->data;
923 GdkPixbufLoader *loader;
924 GString *data;
925
926 if (g_strcmp0 (webkit_web_resource_get_uri (src),
927 web_view->priv->cursor_image_src) != 0)
928 continue;
929
930 data = webkit_web_resource_get_data (src);
931 if (data == NULL)
932 break;
933
934 loader = gdk_pixbuf_loader_new ();
935 if (!gdk_pixbuf_loader_write (loader,
936 (guchar *) data->str, data->len, NULL)) {
937 g_object_unref (loader);
938 break;
939 }
940 gdk_pixbuf_loader_close (loader, NULL);
941
942 if (web_view->priv->cursor_image != NULL)
943 g_object_unref (web_view->priv->cursor_image);
944
945 web_view->priv->cursor_image =
946 g_object_ref (gdk_pixbuf_loader_get_animation (loader));
947
948 g_object_unref (loader);
949 break;
950 }
951 g_list_free (subresources);
952 }
953
954 g_object_unref (test);
955 }
956
957 if (event != NULL && event->button != 3)
958 goto chainup;
959
960 uri = e_web_view_extract_uri (web_view, event);
961
962 g_signal_emit (
963 web_view, signals[POPUP_EVENT], 0,
964 event, uri, &event_handled);
965
966 g_free (uri);
967
968 if (event_handled)
969 return TRUE;
970
971 chainup:
972 /* Chain up to parent's button_press_event() method. */
973 widget_class = GTK_WIDGET_CLASS (e_web_view_parent_class);
974 return widget_class->button_press_event (widget, event);
975 }
976
977 static gboolean
978 web_view_scroll_event (GtkWidget *widget,
979 GdkEventScroll *event)
980 {
981 if (event->state & GDK_CONTROL_MASK) {
982 GdkScrollDirection direction = event->direction;
983
984 if (direction == GDK_SCROLL_SMOOTH) {
985 static gdouble total_delta_y = 0.0;
986
987 total_delta_y += event->delta_y;
988
989 if (total_delta_y >= 1.0) {
990 total_delta_y = 0.0;
991 direction = GDK_SCROLL_DOWN;
992 } else if (total_delta_y <= -1.0) {
993 total_delta_y = 0.0;
994 direction = GDK_SCROLL_UP;
995 } else {
996 return FALSE;
997 }
998 }
999
1000 switch (direction) {
1001 case GDK_SCROLL_UP:
1002 e_web_view_zoom_in (E_WEB_VIEW (widget));
1003 return TRUE;
1004 case GDK_SCROLL_DOWN:
1005 e_web_view_zoom_out (E_WEB_VIEW (widget));
1006 return TRUE;
1007 default:
1008 break;
1009 }
1010 }
1011
1012 return FALSE;
1013 }
1014
1015 static GtkWidget *
1016 web_view_create_plugin_widget (EWebView *web_view,
1017 const gchar *mime_type,
1018 const gchar *uri,
1019 GHashTable *param)
1020 {
1021 GtkWidget *widget = NULL;
1022
1023 if (g_strcmp0 (mime_type, "image/x-themed-icon") == 0) {
1024 GtkIconTheme *icon_theme;
1025 GdkPixbuf *pixbuf;
1026 gpointer data;
1027 glong size = 0;
1028 GError *error = NULL;
1029
1030 icon_theme = gtk_icon_theme_get_default ();
1031
1032 if (size == 0) {
1033 data = g_hash_table_lookup (param, "width");
1034 if (data != NULL)
1035 size = MAX (size, strtol (data, NULL, 10));
1036 }
1037
1038 if (size == 0) {
1039 data = g_hash_table_lookup (param, "height");
1040 if (data != NULL)
1041 size = MAX (size, strtol (data, NULL, 10));
1042 }
1043
1044 if (size == 0)
1045 size = 32; /* arbitrary default */
1046
1047 pixbuf = gtk_icon_theme_load_icon (
1048 icon_theme, uri, size, 0, &error);
1049 if (pixbuf != NULL) {
1050 widget = gtk_image_new_from_pixbuf (pixbuf);
1051 g_object_unref (pixbuf);
1052 } else if (error != NULL) {
1053 g_warning ("%s", error->message);
1054 g_error_free (error);
1055 }
1056 }
1057
1058 return widget;
1059 }
1060
1061 static gchar *
1062 web_view_extract_uri (EWebView *web_view,
1063 GdkEventButton *event)
1064 {
1065 WebKitHitTestResult *result;
1066 WebKitHitTestResultContext context;
1067 gchar *uri = NULL;
1068
1069 result = webkit_web_view_get_hit_test_result (
1070 WEBKIT_WEB_VIEW (web_view), event);
1071
1072 g_object_get (result, "context", &context, "link-uri", &uri, NULL);
1073 g_object_unref (result);
1074
1075 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
1076 return uri;
1077
1078 g_free (uri);
1079
1080 return NULL;
1081 }
1082
1083 static void
1084 web_view_hovering_over_link (EWebView *web_view,
1085 const gchar *title,
1086 const gchar *uri)
1087 {
1088 CamelInternetAddress *address;
1089 CamelURL *curl;
1090 const gchar *format = NULL;
1091 gchar *message = NULL;
1092 gchar *who;
1093
1094 if (uri == NULL || *uri == '\0')
1095 goto exit;
1096
1097 if (g_str_has_prefix (uri, "mailto:"))
1098 format = _("Click to mail %s");
1099 else if (g_str_has_prefix (uri, "callto:"))
1100 format = _("Click to call %s");
1101 else if (g_str_has_prefix (uri, "h323:"))
1102 format = _("Click to call %s");
1103 else if (g_str_has_prefix (uri, "sip:"))
1104 format = _("Click to call %s");
1105 else if (g_str_has_prefix (uri, "##"))
1106 message = g_strdup (_("Click to hide/unhide addresses"));
1107 else
1108 message = g_strdup_printf (_("Click to open %s"), uri);
1109
1110 if (format == NULL)
1111 goto exit;
1112
1113 /* XXX Use something other than Camel here. Surely
1114 * there's other APIs around that can do this. */
1115 curl = camel_url_new (uri, NULL);
1116 address = camel_internet_address_new ();
1117 camel_address_decode (CAMEL_ADDRESS (address), curl->path);
1118 who = camel_address_format (CAMEL_ADDRESS (address));
1119 g_object_unref (address);
1120 camel_url_free (curl);
1121
1122 if (who == NULL)
1123 who = g_strdup (strchr (uri, ':') + 1);
1124
1125 message = g_strdup_printf (format, who);
1126
1127 g_free (who);
1128
1129 exit:
1130 e_web_view_status_message (web_view, message);
1131
1132 g_free (message);
1133 }
1134
1135 static void
1136 web_view_link_clicked (EWebView *web_view,
1137 const gchar *uri)
1138 {
1139 gpointer parent;
1140
1141 if (uri && g_ascii_strncasecmp (uri, "mailto:", 7) == 0) {
1142 gboolean handled = FALSE;
1143
1144 g_signal_emit (
1145 web_view, signals[PROCESS_MAILTO], 0, uri, &handled);
1146
1147 if (handled)
1148 return;
1149 }
1150
1151 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
1152 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
1153
1154 e_show_uri (parent, uri);
1155 }
1156
1157 static void
1158 web_view_load_string (EWebView *web_view,
1159 const gchar *string)
1160 {
1161 if (string == NULL)
1162 string = "";
1163
1164 webkit_web_view_load_string (
1165 WEBKIT_WEB_VIEW (web_view),
1166 string, "text/html", "UTF-8", "evo-file:///");
1167 }
1168
1169 static void
1170 web_view_load_uri (EWebView *web_view,
1171 const gchar *uri)
1172 {
1173 if (uri == NULL)
1174 uri = "about:blank";
1175
1176 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), uri);
1177 }
1178
1179 static void
1180 web_view_frame_load_string (EWebView *web_view,
1181 const gchar *frame_name,
1182 const gchar *string)
1183 {
1184 WebKitWebFrame *main_frame;
1185
1186 if (string == NULL)
1187 string = "";
1188
1189 main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
1190 if (main_frame != NULL) {
1191 WebKitWebFrame *frame;
1192
1193 frame = webkit_web_frame_find_frame (main_frame, frame_name);
1194
1195 if (frame != NULL)
1196 webkit_web_frame_load_string (
1197 frame, string, "text/html",
1198 "UTF-8", "evo-file:///");
1199 }
1200 }
1201
1202 static void
1203 web_view_frame_load_uri (EWebView *web_view,
1204 const gchar *frame_name,
1205 const gchar *uri)
1206 {
1207 WebKitWebFrame *main_frame;
1208
1209 if (uri == NULL)
1210 uri = "about:blank";
1211
1212 main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
1213 if (main_frame != NULL) {
1214 WebKitWebFrame *frame;
1215
1216 frame = webkit_web_frame_find_frame (main_frame, frame_name);
1217
1218 if (frame != NULL)
1219 webkit_web_frame_load_uri (frame, uri);
1220 }
1221 }
1222
1223 static gboolean
1224 web_view_popup_event (EWebView *web_view,
1225 GdkEventButton *event,
1226 const gchar *uri)
1227 {
1228 e_web_view_set_selected_uri (web_view, uri);
1229 e_web_view_show_popup_menu (web_view, event, NULL, NULL);
1230
1231 return TRUE;
1232 }
1233
1234 static void
1235 web_view_stop_loading (EWebView *web_view)
1236 {
1237 webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view));
1238 }
1239
1240 static void
1241 web_view_update_actions (EWebView *web_view,
1242 GdkEventButton *event)
1243 {
1244 GtkActionGroup *action_group;
1245 gboolean can_copy;
1246 gboolean scheme_is_http = FALSE;
1247 gboolean scheme_is_mailto = FALSE;
1248 gboolean uri_is_valid = FALSE;
1249 gboolean has_cursor_image;
1250 gboolean visible;
1251 WebKitHitTestResult *hit_test;
1252 WebKitHitTestResultContext context;
1253 const gchar *group_name;
1254 const gchar *uri;
1255
1256 uri = e_web_view_get_selected_uri (web_view);
1257 can_copy = webkit_web_view_can_copy_clipboard (
1258 WEBKIT_WEB_VIEW (web_view));
1259 hit_test = webkit_web_view_get_hit_test_result (
1260 WEBKIT_WEB_VIEW (web_view), event);
1261 g_object_get (G_OBJECT (hit_test), "context", &context, NULL);
1262
1263 has_cursor_image = (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
1264
1265 /* Parse the URI early so we know if the actions will work. */
1266 if (uri != NULL) {
1267 CamelURL *curl;
1268
1269 curl = camel_url_new (uri, NULL);
1270 uri_is_valid = (curl != NULL);
1271 camel_url_free (curl);
1272
1273 scheme_is_http =
1274 (g_ascii_strncasecmp (uri, "http:", 5) == 0) ||
1275 (g_ascii_strncasecmp (uri, "https:", 6) == 0);
1276
1277 scheme_is_mailto =
1278 (g_ascii_strncasecmp (uri, "mailto:", 7) == 0);
1279 }
1280
1281 /* Allow copying the URI even if it's malformed. */
1282 group_name = "uri";
1283 visible = (uri != NULL) && !scheme_is_mailto;
1284 action_group = e_web_view_get_action_group (web_view, group_name);
1285 gtk_action_group_set_visible (action_group, visible);
1286
1287 group_name = "http";
1288 visible = uri_is_valid && scheme_is_http;
1289 action_group = e_web_view_get_action_group (web_view, group_name);
1290 gtk_action_group_set_visible (action_group, visible);
1291
1292 group_name = "mailto";
1293 visible = uri_is_valid && scheme_is_mailto;
1294 action_group = e_web_view_get_action_group (web_view, group_name);
1295 gtk_action_group_set_visible (action_group, visible);
1296
1297 group_name = "image";
1298 visible = has_cursor_image;
1299 action_group = e_web_view_get_action_group (web_view, group_name);
1300 gtk_action_group_set_visible (action_group, visible);
1301
1302 group_name = "selection";
1303 visible = can_copy;
1304 action_group = e_web_view_get_action_group (web_view, group_name);
1305 gtk_action_group_set_visible (action_group, visible);
1306
1307 group_name = "standard";
1308 visible = (uri == NULL);
1309 action_group = e_web_view_get_action_group (web_view, group_name);
1310 gtk_action_group_set_visible (action_group, visible);
1311
1312 group_name = "lockdown-printing";
1313 visible = (uri == NULL) && !web_view->priv->disable_printing;
1314 action_group = e_web_view_get_action_group (web_view, group_name);
1315 gtk_action_group_set_visible (action_group, visible);
1316
1317 group_name = "lockdown-save-to-disk";
1318 visible = (uri == NULL) && !web_view->priv->disable_save_to_disk;
1319 action_group = e_web_view_get_action_group (web_view, group_name);
1320 gtk_action_group_set_visible (action_group, visible);
1321 }
1322
1323 static void
1324 web_view_submit_alert (EAlertSink *alert_sink,
1325 EAlert *alert)
1326 {
1327 EWebView *web_view;
1328 GtkWidget *dialog;
1329 GString *buffer;
1330 const gchar *icon_name = NULL;
1331 gpointer parent;
1332
1333 web_view = E_WEB_VIEW (alert_sink);
1334
1335 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
1336 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
1337
1338 switch (e_alert_get_message_type (alert)) {
1339 case GTK_MESSAGE_INFO:
1340 icon_name = GTK_STOCK_DIALOG_INFO;
1341 break;
1342
1343 case GTK_MESSAGE_WARNING:
1344 icon_name = GTK_STOCK_DIALOG_WARNING;
1345 break;
1346
1347 case GTK_MESSAGE_ERROR:
1348 icon_name = GTK_STOCK_DIALOG_ERROR;
1349 break;
1350
1351 default:
1352 dialog = e_alert_dialog_new (parent, alert);
1353 gtk_dialog_run (GTK_DIALOG (dialog));
1354 gtk_widget_destroy (dialog);
1355 return;
1356 }
1357
1358 buffer = g_string_sized_new (512);
1359
1360 g_string_append (
1361 buffer,
1362 "<html>"
1363 "<head>"
1364 "<meta http-equiv=\"content-type\""
1365 " content=\"text/html; charset=utf-8\">"
1366 "</head>"
1367 "<body>");
1368
1369 g_string_append (
1370 buffer,
1371 "<table bgcolor='#000000' width='100%'"
1372 " cellpadding='1' cellspacing='0'>"
1373 "<tr>"
1374 "<td>"
1375 "<table bgcolor='#dddddd' width='100%' cellpadding='6'>"
1376 "<tr>");
1377
1378 g_string_append_printf (
1379 buffer,
1380 "<tr>"
1381 "<td valign='top'>"
1382 "<img src='gtk-stock://%s/?size=%d'/>"
1383 "</td>"
1384 "<td align='left' width='100%%'>"
1385 "<h3>%s</h3>"
1386 "%s"
1387 "</td>"
1388 "</tr>",
1389 icon_name,
1390 GTK_ICON_SIZE_DIALOG,
1391 e_alert_get_primary_text (alert),
1392 e_alert_get_secondary_text (alert));
1393
1394 g_string_append (
1395 buffer,
1396 "</table>"
1397 "</td>"
1398 "</tr>"
1399 "</table>"
1400 "</body>"
1401 "</html>");
1402
1403 e_web_view_load_string (web_view, buffer->str);
1404
1405 g_string_free (buffer, TRUE);
1406 }
1407
1408 static void
1409 web_view_selectable_update_actions (ESelectable *selectable,
1410 EFocusTracker *focus_tracker,
1411 GdkAtom *clipboard_targets,
1412 gint n_clipboard_targets)
1413 {
1414 WebKitWebView *web_view;
1415 GtkAction *action;
1416 gboolean sensitive;
1417 const gchar *tooltip;
1418
1419 web_view = WEBKIT_WEB_VIEW (selectable);
1420
1421 action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
1422 sensitive = webkit_web_view_can_cut_clipboard (web_view);
1423 tooltip = _("Cut the selection");
1424 gtk_action_set_sensitive (action, sensitive);
1425 gtk_action_set_tooltip (action, tooltip);
1426
1427 action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
1428 sensitive = webkit_web_view_can_copy_clipboard (web_view);
1429 tooltip = _("Copy the selection");
1430 gtk_action_set_sensitive (action, sensitive);
1431 gtk_action_set_tooltip (action, tooltip);
1432
1433 action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
1434 sensitive = webkit_web_view_can_paste_clipboard (web_view);
1435 tooltip = _("Paste the clipboard");
1436 gtk_action_set_sensitive (action, sensitive);
1437 gtk_action_set_tooltip (action, tooltip);
1438
1439 action = e_focus_tracker_get_select_all_action (focus_tracker);
1440 sensitive = TRUE;
1441 tooltip = _("Select all text and images");
1442 gtk_action_set_sensitive (action, sensitive);
1443 gtk_action_set_tooltip (action, tooltip);
1444 }
1445
1446 static void
1447 web_view_selectable_cut_clipboard (ESelectable *selectable)
1448 {
1449 e_web_view_cut_clipboard (E_WEB_VIEW (selectable));
1450 }
1451
1452 static void
1453 web_view_selectable_copy_clipboard (ESelectable *selectable)
1454 {
1455 e_web_view_copy_clipboard (E_WEB_VIEW (selectable));
1456 }
1457
1458 static void
1459 web_view_selectable_paste_clipboard (ESelectable *selectable)
1460 {
1461 e_web_view_paste_clipboard (E_WEB_VIEW (selectable));
1462 }
1463
1464 static void
1465 web_view_selectable_select_all (ESelectable *selectable)
1466 {
1467 e_web_view_select_all (E_WEB_VIEW (selectable));
1468 }
1469
1470 static gboolean
1471 web_view_drag_motion (GtkWidget *widget,
1472 GdkDragContext *context,
1473 gint x,
1474 gint y,
1475 guint time_)
1476 {
1477 return FALSE;
1478 }
1479
1480 static void
1481 e_web_view_class_init (EWebViewClass *class)
1482 {
1483 GObjectClass *object_class;
1484 GtkWidgetClass *widget_class;
1485 #if 0 /* WEBKIT */
1486 GtkHTMLClass *html_class;
1487 #endif
1488
1489 g_type_class_add_private (class, sizeof (EWebViewPrivate));
1490
1491 object_class = G_OBJECT_CLASS (class);
1492 object_class->set_property = web_view_set_property;
1493 object_class->get_property = web_view_get_property;
1494 object_class->dispose = web_view_dispose;
1495 object_class->finalize = web_view_finalize;
1496 object_class->constructed = web_view_constructed;
1497
1498 widget_class = GTK_WIDGET_CLASS (class);
1499 widget_class->button_press_event = web_view_button_press_event;
1500 widget_class->scroll_event = web_view_scroll_event;
1501 widget_class->drag_motion = web_view_drag_motion;
1502
1503 #if 0 /* WEBKIT */
1504 html_class = GTK_HTML_CLASS (class);
1505 html_class->url_requested = web_view_url_requested;
1506 #endif
1507
1508 class->create_plugin_widget = web_view_create_plugin_widget;
1509 class->extract_uri = web_view_extract_uri;
1510 class->hovering_over_link = web_view_hovering_over_link;
1511 class->link_clicked = web_view_link_clicked;
1512 class->load_string = web_view_load_string;
1513 class->load_uri = web_view_load_uri;
1514 class->frame_load_string = web_view_frame_load_string;
1515 class->frame_load_uri = web_view_frame_load_uri;
1516 class->popup_event = web_view_popup_event;
1517 class->stop_loading = web_view_stop_loading;
1518 class->update_actions = web_view_update_actions;
1519
1520 g_object_class_install_property (
1521 object_class,
1522 PROP_CARET_MODE,
1523 g_param_spec_boolean (
1524 "caret-mode",
1525 "Caret Mode",
1526 NULL,
1527 FALSE,
1528 G_PARAM_READWRITE));
1529
1530 g_object_class_install_property (
1531 object_class,
1532 PROP_CURSOR_IMAGE,
1533 g_param_spec_object (
1534 "cursor-image",
1535 "Image animation at the mouse cursor",
1536 NULL,
1537 GDK_TYPE_PIXBUF_ANIMATION,
1538 G_PARAM_READWRITE));
1539
1540 g_object_class_install_property (
1541 object_class,
1542 PROP_CURSOR_IMAGE_SRC,
1543 g_param_spec_string (
1544 "cursor-image-src",
1545 "Image source uri at the mouse cursor",
1546 NULL,
1547 NULL,
1548 G_PARAM_READWRITE));
1549
1550 g_object_class_install_property (
1551 object_class,
1552 PROP_DISABLE_PRINTING,
1553 g_param_spec_boolean (
1554 "disable-printing",
1555 "Disable Printing",
1556 NULL,
1557 FALSE,
1558 G_PARAM_READWRITE |
1559 G_PARAM_CONSTRUCT));
1560
1561 g_object_class_install_property (
1562 object_class,
1563 PROP_DISABLE_SAVE_TO_DISK,
1564 g_param_spec_boolean (
1565 "disable-save-to-disk",
1566 "Disable Save-to-Disk",
1567 NULL,
1568 FALSE,
1569 G_PARAM_READWRITE |
1570 G_PARAM_CONSTRUCT));
1571
1572 g_object_class_install_property (
1573 object_class,
1574 PROP_INLINE_SPELLING,
1575 g_param_spec_boolean (
1576 "inline-spelling",
1577 "Inline Spelling",
1578 NULL,
1579 FALSE,
1580 G_PARAM_READWRITE));
1581
1582 g_object_class_install_property (
1583 object_class,
1584 PROP_MAGIC_LINKS,
1585 g_param_spec_boolean (
1586 "magic-links",
1587 "Magic Links",
1588 NULL,
1589 FALSE,
1590 G_PARAM_READWRITE));
1591
1592 g_object_class_install_property (
1593 object_class,
1594 PROP_MAGIC_SMILEYS,
1595 g_param_spec_boolean (
1596 "magic-smileys",
1597 "Magic Smileys",
1598 NULL,
1599 FALSE,
1600 G_PARAM_READWRITE));
1601
1602 g_object_class_install_property (
1603 object_class,
1604 PROP_OPEN_PROXY,
1605 g_param_spec_object (
1606 "open-proxy",
1607 "Open Proxy",
1608 NULL,
1609 GTK_TYPE_ACTION,
1610 G_PARAM_READWRITE));
1611
1612 g_object_class_install_property (
1613 object_class,
1614 PROP_PRINT_PROXY,
1615 g_param_spec_object (
1616 "print-proxy",
1617 "Print Proxy",
1618 NULL,
1619 GTK_TYPE_ACTION,
1620 G_PARAM_READWRITE));
1621
1622 g_object_class_install_property (
1623 object_class,
1624 PROP_SAVE_AS_PROXY,
1625 g_param_spec_object (
1626 "save-as-proxy",
1627 "Save As Proxy",
1628 NULL,
1629 GTK_TYPE_ACTION,
1630 G_PARAM_READWRITE));
1631
1632 g_object_class_install_property (
1633 object_class,
1634 PROP_SELECTED_URI,
1635 g_param_spec_string (
1636 "selected-uri",
1637 "Selected URI",
1638 NULL,
1639 NULL,
1640 G_PARAM_READWRITE));
1641
1642 signals[POPUP_EVENT] = g_signal_new (
1643 "popup-event",
1644 G_TYPE_FROM_CLASS (class),
1645 G_SIGNAL_RUN_LAST,
1646 G_STRUCT_OFFSET (EWebViewClass, popup_event),
1647 g_signal_accumulator_true_handled, NULL,
1648 e_marshal_BOOLEAN__BOXED_STRING,
1649 G_TYPE_BOOLEAN, 2,
1650 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1651 G_TYPE_STRING);
1652
1653 signals[STATUS_MESSAGE] = g_signal_new (
1654 "status-message",
1655 G_TYPE_FROM_CLASS (class),
1656 G_SIGNAL_RUN_LAST,
1657 G_STRUCT_OFFSET (EWebViewClass, status_message),
1658 NULL, NULL,
1659 g_cclosure_marshal_VOID__STRING,
1660 G_TYPE_NONE, 1,
1661 G_TYPE_STRING);
1662
1663 signals[STOP_LOADING] = g_signal_new (
1664 "stop-loading",
1665 G_TYPE_FROM_CLASS (class),
1666 G_SIGNAL_RUN_LAST,
1667 G_STRUCT_OFFSET (EWebViewClass, stop_loading),
1668 NULL, NULL,
1669 g_cclosure_marshal_VOID__VOID,
1670 G_TYPE_NONE, 0);
1671
1672 signals[UPDATE_ACTIONS] = g_signal_new (
1673 "update-actions",
1674 G_TYPE_FROM_CLASS (class),
1675 G_SIGNAL_RUN_LAST,
1676 G_STRUCT_OFFSET (EWebViewClass, update_actions),
1677 NULL, NULL,
1678 g_cclosure_marshal_VOID__POINTER,
1679 G_TYPE_NONE, 1, G_TYPE_POINTER);
1680
1681 /* return TRUE when a signal handler processed the mailto URI */
1682 signals[PROCESS_MAILTO] = g_signal_new (
1683 "process-mailto",
1684 G_TYPE_FROM_CLASS (class),
1685 G_SIGNAL_RUN_LAST,
1686 G_STRUCT_OFFSET (EWebViewClass, process_mailto),
1687 NULL, NULL,
1688 e_marshal_BOOLEAN__STRING,
1689 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
1690 }
1691
1692 static void
1693 e_web_view_alert_sink_init (EAlertSinkInterface *interface)
1694 {
1695 interface->submit_alert = web_view_submit_alert;
1696 }
1697
1698 static void
1699 e_web_view_selectable_init (ESelectableInterface *interface)
1700 {
1701 interface->update_actions = web_view_selectable_update_actions;
1702 interface->cut_clipboard = web_view_selectable_cut_clipboard;
1703 interface->copy_clipboard = web_view_selectable_copy_clipboard;
1704 interface->paste_clipboard = web_view_selectable_paste_clipboard;
1705 interface->select_all = web_view_selectable_select_all;
1706 }
1707
1708 static void
1709 e_web_view_init (EWebView *web_view)
1710 {
1711 GtkUIManager *ui_manager;
1712 GtkActionGroup *action_group;
1713 EPopupAction *popup_action;
1714 WebKitWebSettings *web_settings;
1715 GSettingsSchema *settings_schema;
1716 GSettings *settings;
1717 const gchar *domain = GETTEXT_PACKAGE;
1718 const gchar *id;
1719 GError *error = NULL;
1720
1721 web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
1722
1723 web_view->priv->highlights = NULL;
1724
1725 g_signal_connect (
1726 web_view, "create-plugin-widget",
1727 G_CALLBACK (web_view_create_plugin_widget_cb), NULL);
1728
1729 g_signal_connect (
1730 web_view, "hovering-over-link",
1731 G_CALLBACK (web_view_hovering_over_link_cb), NULL);
1732
1733 g_signal_connect (
1734 web_view, "navigation-policy-decision-requested",
1735 G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
1736 NULL);
1737
1738 g_signal_connect (
1739 web_view, "new-window-policy-decision-requested",
1740 G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
1741 NULL);
1742
1743 g_signal_connect (
1744 web_view, "notify::load-status",
1745 G_CALLBACK (web_view_load_status_changed_cb), NULL);
1746
1747 ui_manager = gtk_ui_manager_new ();
1748 web_view->priv->ui_manager = ui_manager;
1749
1750 g_signal_connect_swapped (
1751 ui_manager, "connect-proxy",
1752 G_CALLBACK (web_view_connect_proxy_cb), web_view);
1753
1754 web_settings = e_web_view_get_default_settings ();
1755 e_web_view_set_settings (web_view, web_settings);
1756 g_object_unref (web_settings);
1757
1758 e_web_view_install_request_handler (web_view, E_TYPE_FILE_REQUEST);
1759 e_web_view_install_request_handler (web_view, E_TYPE_STOCK_REQUEST);
1760
1761 settings = g_settings_new ("org.gnome.desktop.interface");
1762 g_signal_connect_swapped (
1763 settings, "changed::font-name",
1764 G_CALLBACK (e_web_view_update_fonts), web_view);
1765 g_signal_connect_swapped (
1766 settings, "changed::monospace-font-name",
1767 G_CALLBACK (e_web_view_update_fonts), web_view);
1768 web_view->priv->font_settings = settings;
1769
1770 /* This schema is optional. Use if available. */
1771 id = "org.gnome.settings-daemon.plugins.xsettings";
1772 settings_schema = g_settings_schema_source_lookup (
1773 g_settings_schema_source_get_default (), id, FALSE);
1774 if (settings_schema != NULL) {
1775 settings = g_settings_new (id);
1776 g_signal_connect_swapped (
1777 settings, "changed::antialiasing",
1778 G_CALLBACK (e_web_view_update_fonts), web_view);
1779 web_view->priv->aliasing_settings = settings;
1780 }
1781
1782 e_web_view_update_fonts (web_view);
1783
1784 action_group = gtk_action_group_new ("uri");
1785 gtk_action_group_set_translation_domain (action_group, domain);
1786 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1787 g_object_unref (action_group);
1788
1789 gtk_action_group_add_actions (
1790 action_group, uri_entries,
1791 G_N_ELEMENTS (uri_entries), web_view);
1792
1793 action_group = gtk_action_group_new ("http");
1794 gtk_action_group_set_translation_domain (action_group, domain);
1795 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1796 g_object_unref (action_group);
1797
1798 gtk_action_group_add_actions (
1799 action_group, http_entries,
1800 G_N_ELEMENTS (http_entries), web_view);
1801
1802 action_group = gtk_action_group_new ("mailto");
1803 gtk_action_group_set_translation_domain (action_group, domain);
1804 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1805 g_object_unref (action_group);
1806
1807 gtk_action_group_add_actions (
1808 action_group, mailto_entries,
1809 G_N_ELEMENTS (mailto_entries), web_view);
1810
1811 action_group = gtk_action_group_new ("image");
1812 gtk_action_group_set_translation_domain (action_group, domain);
1813 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1814 g_object_unref (action_group);
1815
1816 gtk_action_group_add_actions (
1817 action_group, image_entries,
1818 G_N_ELEMENTS (image_entries), web_view);
1819
1820 action_group = gtk_action_group_new ("selection");
1821 gtk_action_group_set_translation_domain (action_group, domain);
1822 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1823 g_object_unref (action_group);
1824
1825 gtk_action_group_add_actions (
1826 action_group, selection_entries,
1827 G_N_ELEMENTS (selection_entries), web_view);
1828
1829 action_group = gtk_action_group_new ("standard");
1830 gtk_action_group_set_translation_domain (action_group, domain);
1831 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1832 g_object_unref (action_group);
1833
1834 gtk_action_group_add_actions (
1835 action_group, standard_entries,
1836 G_N_ELEMENTS (standard_entries), web_view);
1837
1838 popup_action = e_popup_action_new ("open");
1839 gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
1840 g_object_unref (popup_action);
1841
1842 g_object_bind_property (
1843 web_view, "open-proxy",
1844 popup_action, "related-action",
1845 G_BINDING_BIDIRECTIONAL |
1846 G_BINDING_SYNC_CREATE);
1847
1848 /* Support lockdown. */
1849
1850 action_group = gtk_action_group_new ("lockdown-printing");
1851 gtk_action_group_set_translation_domain (action_group, domain);
1852 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1853 g_object_unref (action_group);
1854
1855 popup_action = e_popup_action_new ("print");
1856 gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
1857 g_object_unref (popup_action);
1858
1859 g_object_bind_property (
1860 web_view, "print-proxy",
1861 popup_action, "related-action",
1862 G_BINDING_BIDIRECTIONAL |
1863 G_BINDING_SYNC_CREATE);
1864
1865 action_group = gtk_action_group_new ("lockdown-save-to-disk");
1866 gtk_action_group_set_translation_domain (action_group, domain);
1867 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1868 g_object_unref (action_group);
1869
1870 popup_action = e_popup_action_new ("save-as");
1871 gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
1872 g_object_unref (popup_action);
1873
1874 g_object_bind_property (
1875 web_view, "save-as-proxy",
1876 popup_action, "related-action",
1877 G_BINDING_BIDIRECTIONAL |
1878 G_BINDING_SYNC_CREATE);
1879
1880 /* Because we are loading from a hard-coded string, there is
1881 * no chance of I/O errors. Failure here implies a malformed
1882 * UI definition. Full stop. */
1883 gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
1884 if (error != NULL)
1885 g_error ("%s", error->message);
1886
1887 id = "org.gnome.evolution.webview";
1888 e_plugin_ui_register_manager (ui_manager, id, web_view);
1889 e_plugin_ui_enable_manager (ui_manager, id);
1890 }
1891
1892 GtkWidget *
1893 e_web_view_new (void)
1894 {
1895 return g_object_new (E_TYPE_WEB_VIEW, NULL);
1896 }
1897
1898 void
1899 e_web_view_clear (EWebView *web_view)
1900 {
1901 GtkStyle *style;
1902 gchar *html;
1903
1904 g_return_if_fail (E_IS_WEB_VIEW (web_view));
1905
1906 style = gtk_widget_get_style (GTK_WIDGET (web_view));
1907
1908 html = g_strdup_printf (
1909 "<html><head></head><body bgcolor=\"#%06x\"></body></html>",
1910 e_color_to_value (&style->base[GTK_STATE_NORMAL]));
1911
1912 webkit_web_view_load_html_string (
1913 WEBKIT_WEB_VIEW (web_view), html, NULL);
1914
1915 g_free (html);
1916 }
1917
1918 void
1919 e_web_view_load_string (EWebView *web_view,
1920 const gchar *string)
1921 {
1922 EWebViewClass *class;
1923
1924 g_return_if_fail (E_IS_WEB_VIEW (web_view));
1925
1926 class = E_WEB_VIEW_GET_CLASS (web_view);
1927 g_return_if_fail (class->load_string != NULL);
1928
1929 class->load_string (web_view, string);
1930 }
1931
1932 void
1933 e_web_view_load_uri (EWebView *web_view,
1934 const gchar *uri)
1935 {
1936 EWebViewClass *class;
1937
1938 g_return_if_fail (E_IS_WEB_VIEW (web_view));
1939
1940 class = E_WEB_VIEW_GET_CLASS (web_view);
1941 g_return_if_fail (class->load_uri != NULL);
1942
1943 class->load_uri (web_view, uri);
1944 }
1945
1946 void
1947 e_web_view_reload (EWebView *web_view)
1948 {
1949 g_return_if_fail (E_IS_WEB_VIEW (web_view));
1950
1951 webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
1952 }
1953
1954 const gchar *
1955 e_web_view_get_uri (EWebView *web_view)
1956 {
1957 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
1958
1959 return webkit_web_view_get_uri (WEBKIT_WEB_VIEW (web_view));
1960 }
1961
1962 void
1963 e_web_view_frame_load_string (EWebView *web_view,
1964 const gchar *frame_name,
1965 const gchar *string)
1966 {
1967 EWebViewClass *class;
1968
1969 g_return_if_fail (E_IS_WEB_VIEW (web_view));
1970 g_return_if_fail (frame_name != NULL);
1971
1972 class = E_WEB_VIEW_GET_CLASS (web_view);
1973 g_return_if_fail (class->frame_load_string != NULL);
1974
1975 class->frame_load_string (web_view, frame_name, string);
1976 }
1977
1978 void
1979 e_web_view_frame_load_uri (EWebView *web_view,
1980 const gchar *frame_name,
1981 const gchar *uri)
1982 {
1983 EWebViewClass *class;
1984
1985 g_return_if_fail (E_IS_WEB_VIEW (web_view));
1986 g_return_if_fail (frame_name != NULL);
1987
1988 class = E_WEB_VIEW_GET_CLASS (web_view);
1989 g_return_if_fail (class->frame_load_uri != NULL);
1990
1991 class->frame_load_uri (web_view, frame_name, uri);
1992 }
1993
1994 const gchar *
1995 e_web_view_frame_get_uri (EWebView *web_view,
1996 const gchar *frame_name)
1997 {
1998 WebKitWebFrame *main_frame;
1999
2000 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2001 g_return_val_if_fail (frame_name != NULL, NULL);
2002
2003 main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (web_view));
2004 if (main_frame != NULL) {
2005 WebKitWebFrame *frame;
2006
2007 frame = webkit_web_frame_find_frame (main_frame, frame_name);
2008
2009 if (frame != NULL)
2010 return webkit_web_frame_get_uri (frame);
2011 }
2012
2013 return NULL;
2014 }
2015
2016 gchar *
2017 e_web_view_get_html (EWebView *web_view)
2018 {
2019 WebKitDOMDocument *document;
2020 WebKitDOMElement *element;
2021
2022 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2023
2024 document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
2025 element = webkit_dom_document_get_document_element (document);
2026
2027 return webkit_dom_html_element_get_outer_html (
2028 WEBKIT_DOM_HTML_ELEMENT (element));
2029 }
2030
2031 gboolean
2032 e_web_view_get_caret_mode (EWebView *web_view)
2033 {
2034 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2035
2036 return web_view->priv->caret_mode;
2037 }
2038
2039 void
2040 e_web_view_set_caret_mode (EWebView *web_view,
2041 gboolean caret_mode)
2042 {
2043 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2044
2045 if (web_view->priv->caret_mode == caret_mode)
2046 return;
2047
2048 web_view->priv->caret_mode = caret_mode;
2049
2050 g_object_notify (G_OBJECT (web_view), "caret-mode");
2051 }
2052
2053 GtkTargetList *
2054 e_web_view_get_copy_target_list (EWebView *web_view)
2055 {
2056 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2057
2058 return webkit_web_view_get_copy_target_list (
2059 WEBKIT_WEB_VIEW (web_view));
2060 }
2061
2062 gboolean
2063 e_web_view_get_disable_printing (EWebView *web_view)
2064 {
2065 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2066
2067 return web_view->priv->disable_printing;
2068 }
2069
2070 void
2071 e_web_view_set_disable_printing (EWebView *web_view,
2072 gboolean disable_printing)
2073 {
2074 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2075
2076 if (web_view->priv->disable_printing == disable_printing)
2077 return;
2078
2079 web_view->priv->disable_printing = disable_printing;
2080
2081 g_object_notify (G_OBJECT (web_view), "disable-printing");
2082 }
2083
2084 gboolean
2085 e_web_view_get_disable_save_to_disk (EWebView *web_view)
2086 {
2087 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2088
2089 return web_view->priv->disable_save_to_disk;
2090 }
2091
2092 void
2093 e_web_view_set_disable_save_to_disk (EWebView *web_view,
2094 gboolean disable_save_to_disk)
2095 {
2096 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2097
2098 if (web_view->priv->disable_save_to_disk == disable_save_to_disk)
2099 return;
2100
2101 web_view->priv->disable_save_to_disk = disable_save_to_disk;
2102
2103 g_object_notify (G_OBJECT (web_view), "disable-save-to-disk");
2104 }
2105
2106 gboolean
2107 e_web_view_get_enable_frame_flattening (EWebView *web_view)
2108 {
2109 WebKitWebSettings *settings;
2110 gboolean flattening;
2111
2112 /* Return TRUE with fail since it's default value we set in _init(). */
2113 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), TRUE);
2114
2115 settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
2116 g_return_val_if_fail (settings != NULL, TRUE);
2117
2118 g_object_get (
2119 G_OBJECT (settings),
2120 "enable-frame-flattening", &flattening, NULL);
2121
2122 return flattening;
2123 }
2124
2125 void
2126 e_web_view_set_enable_frame_flattening (EWebView *web_view,
2127 gboolean enable_frame_flattening)
2128 {
2129 WebKitWebSettings *settings;
2130
2131 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2132
2133 settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
2134 g_return_if_fail (settings != NULL);
2135
2136 g_object_set (
2137 G_OBJECT (settings), "enable-frame-flattening",
2138 enable_frame_flattening, NULL);
2139 }
2140
2141 gboolean
2142 e_web_view_get_editable (EWebView *web_view)
2143 {
2144 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2145
2146 return webkit_web_view_get_editable (WEBKIT_WEB_VIEW (web_view));
2147 }
2148
2149 void
2150 e_web_view_set_editable (EWebView *web_view,
2151 gboolean editable)
2152 {
2153 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2154
2155 webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view), editable);
2156 }
2157
2158 gboolean
2159 e_web_view_get_inline_spelling (EWebView *web_view)
2160 {
2161 #if 0 /* WEBKIT - XXX No equivalent property? */
2162 /* XXX This is just here to maintain symmetry
2163 * with e_web_view_set_inline_spelling(). */
2164
2165 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2166
2167 return gtk_html_get_inline_spelling (GTK_HTML (web_view));
2168 #endif
2169
2170 return FALSE;
2171 }
2172
2173 void
2174 e_web_view_set_inline_spelling (EWebView *web_view,
2175 gboolean inline_spelling)
2176 {
2177 #if 0 /* WEBKIT - XXX No equivalent property? */
2178 /* XXX GtkHTML does not utilize GObject properties as well
2179 * as it could. This just wraps gtk_html_set_inline_spelling()
2180 * so we get a "notify::inline-spelling" signal. */
2181
2182 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2183
2184 gtk_html_set_inline_spelling (GTK_HTML (web_view), inline_spelling);
2185
2186 g_object_notify (G_OBJECT (web_view), "inline-spelling");
2187 #endif
2188 }
2189
2190 gboolean
2191 e_web_view_get_magic_links (EWebView *web_view)
2192 {
2193 #if 0 /* WEBKIT - XXX No equivalent property? */
2194 /* XXX This is just here to maintain symmetry
2195 * with e_web_view_set_magic_links(). */
2196
2197 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2198
2199 return gtk_html_get_magic_links (GTK_HTML (web_view));
2200 #endif
2201
2202 return FALSE;
2203 }
2204
2205 void
2206 e_web_view_set_magic_links (EWebView *web_view,
2207 gboolean magic_links)
2208 {
2209 #if 0 /* WEBKIT - XXX No equivalent property? */
2210 /* XXX GtkHTML does not utilize GObject properties as well
2211 * as it could. This just wraps gtk_html_set_magic_links()
2212 * so we can get a "notify::magic-links" signal. */
2213
2214 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2215
2216 gtk_html_set_magic_links (GTK_HTML (web_view), magic_links);
2217
2218 g_object_notify (G_OBJECT (web_view), "magic-links");
2219 #endif
2220 }
2221
2222 gboolean
2223 e_web_view_get_magic_smileys (EWebView *web_view)
2224 {
2225 #if 0 /* WEBKIT - No equivalent property? */
2226 /* XXX This is just here to maintain symmetry
2227 * with e_web_view_set_magic_smileys(). */
2228
2229 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2230
2231 return gtk_html_get_magic_smileys (GTK_HTML (web_view));
2232 #endif
2233
2234 return FALSE;
2235 }
2236
2237 void
2238 e_web_view_set_magic_smileys (EWebView *web_view,
2239 gboolean magic_smileys)
2240 {
2241 #if 0 /* WEBKIT - No equivalent property? */
2242 /* XXX GtkHTML does not utilize GObject properties as well
2243 * as it could. This just wraps gtk_html_set_magic_smileys()
2244 * so we can get a "notify::magic-smileys" signal. */
2245
2246 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2247
2248 gtk_html_set_magic_smileys (GTK_HTML (web_view), magic_smileys);
2249
2250 g_object_notify (G_OBJECT (web_view), "magic-smileys");
2251 #endif
2252 }
2253
2254 const gchar *
2255 e_web_view_get_selected_uri (EWebView *web_view)
2256 {
2257 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2258
2259 return web_view->priv->selected_uri;
2260 }
2261
2262 void
2263 e_web_view_set_selected_uri (EWebView *web_view,
2264 const gchar *selected_uri)
2265 {
2266 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2267
2268 if (g_strcmp0 (web_view->priv->selected_uri, selected_uri) == 0)
2269 return;
2270
2271 g_free (web_view->priv->selected_uri);
2272 web_view->priv->selected_uri = g_strdup (selected_uri);
2273
2274 g_object_notify (G_OBJECT (web_view), "selected-uri");
2275 }
2276
2277 GdkPixbufAnimation *
2278 e_web_view_get_cursor_image (EWebView *web_view)
2279 {
2280 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2281
2282 return web_view->priv->cursor_image;
2283 }
2284
2285 void
2286 e_web_view_set_cursor_image (EWebView *web_view,
2287 GdkPixbufAnimation *image)
2288 {
2289 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2290
2291 if (web_view->priv->cursor_image == image)
2292 return;
2293
2294 if (image != NULL)
2295 g_object_ref (image);
2296
2297 if (web_view->priv->cursor_image != NULL)
2298 g_object_unref (web_view->priv->cursor_image);
2299
2300 web_view->priv->cursor_image = image;
2301
2302 g_object_notify (G_OBJECT (web_view), "cursor-image");
2303 }
2304
2305 const gchar *
2306 e_web_view_get_cursor_image_src (EWebView *web_view)
2307 {
2308 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2309
2310 return web_view->priv->cursor_image_src;
2311 }
2312
2313 void
2314 e_web_view_set_cursor_image_src (EWebView *web_view,
2315 const gchar *src_uri)
2316 {
2317 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2318
2319 if (g_strcmp0 (web_view->priv->cursor_image_src, src_uri) == 0)
2320 return;
2321
2322 g_free (web_view->priv->cursor_image_src);
2323 web_view->priv->cursor_image_src = g_strdup (src_uri);
2324
2325 g_object_notify (G_OBJECT (web_view), "cursor-image-src");
2326 }
2327
2328 GtkAction *
2329 e_web_view_get_open_proxy (EWebView *web_view)
2330 {
2331 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2332
2333 return web_view->priv->open_proxy;
2334 }
2335
2336 void
2337 e_web_view_set_open_proxy (EWebView *web_view,
2338 GtkAction *open_proxy)
2339 {
2340 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2341
2342 if (web_view->priv->open_proxy == open_proxy)
2343 return;
2344
2345 if (open_proxy != NULL) {
2346 g_return_if_fail (GTK_IS_ACTION (open_proxy));
2347 g_object_ref (open_proxy);
2348 }
2349
2350 if (web_view->priv->open_proxy != NULL)
2351 g_object_unref (web_view->priv->open_proxy);
2352
2353 web_view->priv->open_proxy = open_proxy;
2354
2355 g_object_notify (G_OBJECT (web_view), "open-proxy");
2356 }
2357
2358 GtkTargetList *
2359 e_web_view_get_paste_target_list (EWebView *web_view)
2360 {
2361 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2362
2363 return webkit_web_view_get_paste_target_list (
2364 WEBKIT_WEB_VIEW (web_view));
2365 }
2366
2367 GtkAction *
2368 e_web_view_get_print_proxy (EWebView *web_view)
2369 {
2370 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2371
2372 return web_view->priv->print_proxy;
2373 }
2374
2375 void
2376 e_web_view_set_print_proxy (EWebView *web_view,
2377 GtkAction *print_proxy)
2378 {
2379 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2380
2381 if (web_view->priv->print_proxy == print_proxy)
2382 return;
2383
2384 if (print_proxy != NULL) {
2385 g_return_if_fail (GTK_IS_ACTION (print_proxy));
2386 g_object_ref (print_proxy);
2387 }
2388
2389 if (web_view->priv->print_proxy != NULL)
2390 g_object_unref (web_view->priv->print_proxy);
2391
2392 web_view->priv->print_proxy = print_proxy;
2393
2394 g_object_notify (G_OBJECT (web_view), "print-proxy");
2395 }
2396
2397 GtkAction *
2398 e_web_view_get_save_as_proxy (EWebView *web_view)
2399 {
2400 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2401
2402 return web_view->priv->save_as_proxy;
2403 }
2404
2405 void
2406 e_web_view_set_save_as_proxy (EWebView *web_view,
2407 GtkAction *save_as_proxy)
2408 {
2409 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2410
2411 if (web_view->priv->save_as_proxy == save_as_proxy)
2412 return;
2413
2414 if (save_as_proxy != NULL) {
2415 g_return_if_fail (GTK_IS_ACTION (save_as_proxy));
2416 g_object_ref (save_as_proxy);
2417 }
2418
2419 if (web_view->priv->save_as_proxy != NULL)
2420 g_object_unref (web_view->priv->save_as_proxy);
2421
2422 web_view->priv->save_as_proxy = save_as_proxy;
2423
2424 g_object_notify (G_OBJECT (web_view), "save-as-proxy");
2425 }
2426
2427 GSList *
2428 e_web_view_get_highlights (EWebView *web_view)
2429 {
2430 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2431
2432 return web_view->priv->highlights;
2433 }
2434
2435 void
2436 e_web_view_add_highlight (EWebView *web_view,
2437 const gchar *highlight)
2438 {
2439 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2440 g_return_if_fail (highlight && *highlight);
2441
2442 web_view->priv->highlights = g_slist_append (
2443 web_view->priv->highlights, g_strdup (highlight));
2444
2445 web_view_update_document_highlights (web_view);
2446 }
2447
2448 void e_web_view_clear_highlights (EWebView *web_view)
2449 {
2450 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2451
2452 if (!web_view->priv->highlights)
2453 return;
2454
2455 g_slist_free_full (web_view->priv->highlights, g_free);
2456 web_view->priv->highlights = NULL;
2457
2458 web_view_update_document_highlights (web_view);
2459 }
2460
2461 GtkAction *
2462 e_web_view_get_action (EWebView *web_view,
2463 const gchar *action_name)
2464 {
2465 GtkUIManager *ui_manager;
2466
2467 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2468 g_return_val_if_fail (action_name != NULL, NULL);
2469
2470 ui_manager = e_web_view_get_ui_manager (web_view);
2471
2472 return e_lookup_action (ui_manager, action_name);
2473 }
2474
2475 GtkActionGroup *
2476 e_web_view_get_action_group (EWebView *web_view,
2477 const gchar *group_name)
2478 {
2479 GtkUIManager *ui_manager;
2480
2481 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2482 g_return_val_if_fail (group_name != NULL, NULL);
2483
2484 ui_manager = e_web_view_get_ui_manager (web_view);
2485
2486 return e_lookup_action_group (ui_manager, group_name);
2487 }
2488
2489 gchar *
2490 e_web_view_extract_uri (EWebView *web_view,
2491 GdkEventButton *event)
2492 {
2493 EWebViewClass *class;
2494
2495 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2496
2497 class = E_WEB_VIEW_GET_CLASS (web_view);
2498 g_return_val_if_fail (class->extract_uri != NULL, NULL);
2499
2500 return class->extract_uri (web_view, event);
2501 }
2502
2503 void
2504 e_web_view_copy_clipboard (EWebView *web_view)
2505 {
2506 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2507
2508 webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
2509 }
2510
2511 void
2512 e_web_view_cut_clipboard (EWebView *web_view)
2513 {
2514 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2515
2516 webkit_web_view_cut_clipboard (WEBKIT_WEB_VIEW (web_view));
2517 }
2518
2519 gboolean
2520 e_web_view_is_selection_active (EWebView *web_view)
2521 {
2522 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2523
2524 return webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view));
2525 }
2526
2527 void
2528 e_web_view_paste_clipboard (EWebView *web_view)
2529 {
2530 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2531
2532 webkit_web_view_paste_clipboard (WEBKIT_WEB_VIEW (web_view));
2533 }
2534
2535 gboolean
2536 e_web_view_scroll_forward (EWebView *web_view)
2537 {
2538 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2539
2540 webkit_web_view_move_cursor (
2541 WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, 1);
2542
2543 return TRUE; /* XXX This means nothing. */
2544 }
2545
2546 gboolean
2547 e_web_view_scroll_backward (EWebView *web_view)
2548 {
2549 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
2550
2551 webkit_web_view_move_cursor (
2552 WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, -1);
2553
2554 return TRUE; /* XXX This means nothing. */
2555 }
2556
2557 void
2558 e_web_view_select_all (EWebView *web_view)
2559 {
2560 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2561
2562 webkit_web_view_select_all (WEBKIT_WEB_VIEW (web_view));
2563 }
2564
2565 void
2566 e_web_view_unselect_all (EWebView *web_view)
2567 {
2568 #if 0 /* WEBKIT */
2569 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2570
2571 gtk_html_command (GTK_HTML (web_view), "unselect-all");
2572 #endif
2573 }
2574
2575 void
2576 e_web_view_zoom_100 (EWebView *web_view)
2577 {
2578 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2579
2580 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), 1.0);
2581 }
2582
2583 void
2584 e_web_view_zoom_in (EWebView *web_view)
2585 {
2586 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2587
2588 webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
2589 }
2590
2591 void
2592 e_web_view_zoom_out (EWebView *web_view)
2593 {
2594 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2595
2596 webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
2597 }
2598
2599 GtkUIManager *
2600 e_web_view_get_ui_manager (EWebView *web_view)
2601 {
2602 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2603
2604 return web_view->priv->ui_manager;
2605 }
2606
2607 GtkWidget *
2608 e_web_view_get_popup_menu (EWebView *web_view)
2609 {
2610 GtkUIManager *ui_manager;
2611 GtkWidget *menu;
2612
2613 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2614
2615 ui_manager = e_web_view_get_ui_manager (web_view);
2616 menu = gtk_ui_manager_get_widget (ui_manager, "/context");
2617 g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
2618
2619 return menu;
2620 }
2621
2622 void
2623 e_web_view_show_popup_menu (EWebView *web_view,
2624 GdkEventButton *event,
2625 GtkMenuPositionFunc func,
2626 gpointer user_data)
2627 {
2628 GtkWidget *menu;
2629
2630 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2631
2632 e_web_view_update_actions (web_view, event);
2633
2634 menu = e_web_view_get_popup_menu (web_view);
2635
2636 if (event != NULL)
2637 gtk_menu_popup (
2638 GTK_MENU (menu), NULL, NULL, func,
2639 user_data, event->button, event->time);
2640 else
2641 gtk_menu_popup (
2642 GTK_MENU (menu), NULL, NULL, func,
2643 user_data, 0, gtk_get_current_event_time ());
2644 }
2645
2646 void
2647 e_web_view_status_message (EWebView *web_view,
2648 const gchar *status_message)
2649 {
2650 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2651
2652 g_signal_emit (web_view, signals[STATUS_MESSAGE], 0, status_message);
2653 }
2654
2655 void
2656 e_web_view_stop_loading (EWebView *web_view)
2657 {
2658 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2659
2660 g_signal_emit (web_view, signals[STOP_LOADING], 0);
2661 }
2662
2663 void
2664 e_web_view_update_actions (EWebView *web_view,
2665 GdkEventButton *event)
2666 {
2667 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2668
2669 g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0, event);
2670 }
2671
2672 static gchar *
2673 web_view_get_frame_selection_html (WebKitDOMElement *iframe)
2674 {
2675 WebKitDOMDocument *document;
2676 WebKitDOMDOMWindow *window;
2677 WebKitDOMDOMSelection *selection;
2678 WebKitDOMNodeList *frames;
2679 gulong ii, length;
2680
2681 document = webkit_dom_html_iframe_element_get_content_document (
2682 WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
2683 window = webkit_dom_document_get_default_view (document);
2684 selection = webkit_dom_dom_window_get_selection (window);
2685 if (selection && (webkit_dom_dom_selection_get_range_count (selection) > 0)) {
2686 WebKitDOMRange *range;
2687 WebKitDOMElement *element;
2688 WebKitDOMDocumentFragment *fragment;
2689
2690 range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
2691 if (range != NULL) {
2692 fragment = webkit_dom_range_clone_contents (
2693 range, NULL);
2694
2695 element = webkit_dom_document_create_element (
2696 document, "DIV", NULL);
2697 webkit_dom_node_append_child (
2698 WEBKIT_DOM_NODE (element),
2699 WEBKIT_DOM_NODE (fragment), NULL);
2700
2701 return webkit_dom_html_element_get_inner_html (
2702 WEBKIT_DOM_HTML_ELEMENT (element));
2703 }
2704 }
2705
2706 frames = webkit_dom_document_get_elements_by_tag_name (
2707 document, "IFRAME");
2708 length = webkit_dom_node_list_get_length (frames);
2709 for (ii = 0; ii < length; ii++) {
2710 WebKitDOMNode *node;
2711 gchar *text;
2712
2713 node = webkit_dom_node_list_item (frames, ii);
2714
2715 text = web_view_get_frame_selection_html (
2716 WEBKIT_DOM_ELEMENT (node));
2717
2718 if (text != NULL)
2719 return text;
2720 }
2721
2722 return NULL;
2723 }
2724
2725 gchar *
2726 e_web_view_get_selection_html (EWebView *web_view)
2727 {
2728 WebKitDOMDocument *document;
2729 WebKitDOMNodeList *frames;
2730 gulong ii, length;
2731
2732 g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
2733
2734 if (!webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view)))
2735 return NULL;
2736
2737 document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
2738 frames = webkit_dom_document_get_elements_by_tag_name (document, "IFRAME");
2739 length = webkit_dom_node_list_get_length (frames);
2740
2741 for (ii = 0; ii < length; ii++) {
2742 gchar *text;
2743 WebKitDOMNode *node;
2744
2745 node = webkit_dom_node_list_item (frames, ii);
2746
2747 text = web_view_get_frame_selection_html (
2748 WEBKIT_DOM_ELEMENT (node));
2749
2750 if (text != NULL)
2751 return text;
2752 }
2753
2754 return NULL;
2755 }
2756
2757 void
2758 e_web_view_set_settings (EWebView *web_view,
2759 WebKitWebSettings *settings)
2760 {
2761 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2762
2763 if (settings == webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view)))
2764 return;
2765
2766 g_object_bind_property (
2767 settings, "enable-caret-browsing",
2768 web_view, "caret-mode",
2769 G_BINDING_BIDIRECTIONAL |
2770 G_BINDING_SYNC_CREATE);
2771
2772 webkit_web_view_set_settings (WEBKIT_WEB_VIEW (web_view), settings);
2773 }
2774
2775 WebKitWebSettings *
2776 e_web_view_get_default_settings (void)
2777 {
2778 WebKitWebSettings *settings;
2779
2780 settings = webkit_web_settings_new ();
2781
2782 g_object_set (
2783 G_OBJECT (settings),
2784 "enable-frame-flattening", TRUE,
2785 "enable-java-applet", FALSE,
2786 "enable-html5-database", FALSE,
2787 "enable-html5-local-storage", FALSE,
2788 "enable-offline-web-application-cache", FALSE,
2789 "enable-site-specific-quirks", TRUE,
2790 "enable-scripts", FALSE,
2791 NULL);
2792
2793 return settings;
2794 }
2795
2796 void
2797 e_web_view_update_fonts (EWebView *web_view)
2798 {
2799 EWebViewClass *class;
2800 GString *stylesheet;
2801 gchar *base64;
2802 gchar *aa = NULL;
2803 WebKitWebSettings *settings;
2804 PangoFontDescription *min_size, *ms, *vw;
2805 const gchar *styles[] = { "normal", "oblique", "italic" };
2806 const gchar *smoothing = NULL;
2807 GtkStyleContext *context;
2808 GdkColor *link = NULL;
2809 GdkColor *visited = NULL;
2810
2811 g_return_if_fail (E_IS_WEB_VIEW (web_view));
2812
2813 ms = NULL;
2814 vw = NULL;
2815
2816 class = E_WEB_VIEW_GET_CLASS (web_view);
2817 if (class->set_fonts != NULL)
2818 class->set_fonts (web_view, &ms, &vw);
2819
2820 if (ms == NULL) {
2821 gchar *font;
2822
2823 font = g_settings_get_string (
2824 web_view->priv->font_settings,
2825 "monospace-font-name");
2826
2827 ms = pango_font_description_from_string (
2828 (font != NULL) ? font : "monospace 10");
2829
2830 g_free (font);
2831 }
2832
2833 if (vw == NULL) {
2834 gchar *font;
2835
2836 font = g_settings_get_string (
2837 web_view->priv->font_settings,
2838 "font-name");
2839
2840 vw = pango_font_description_from_string (
2841 (font != NULL) ? font : "serif 10");
2842
2843 g_free (font);
2844 }
2845
2846 if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw)) {
2847 min_size = ms;
2848 } else {
2849 min_size = vw;
2850 }
2851
2852 stylesheet = g_string_new ("");
2853 g_string_append_printf (
2854 stylesheet,
2855 "body {\n"
2856 " font-family: '%s';\n"
2857 " font-size: %dpt;\n"
2858 " font-weight: %d;\n"
2859 " font-style: %s;\n",
2860 pango_font_description_get_family (vw),
2861 pango_font_description_get_size (vw) / PANGO_SCALE,
2862 pango_font_description_get_weight (vw),
2863 styles[pango_font_description_get_style (vw)]);
2864
2865 if (web_view->priv->aliasing_settings != NULL)
2866 aa = g_settings_get_string (
2867 web_view->priv->aliasing_settings, "antialiasing");
2868
2869 if (g_strcmp0 (aa, "none") == 0)
2870 smoothing = "none";
2871 else if (g_strcmp0 (aa, "grayscale") == 0)
2872 smoothing = "antialiased";
2873 else if (g_strcmp0 (aa, "rgba") == 0)
2874 smoothing = "subpixel-antialiased";
2875
2876 if (smoothing != NULL)
2877 g_string_append_printf (
2878 stylesheet,
2879 " -webkit-font-smoothing: %s;\n",
2880 smoothing);
2881
2882 g_free (aa);
2883
2884 g_string_append (stylesheet, "}\n");
2885
2886 g_string_append_printf (
2887 stylesheet,
2888 "pre,code,.pre {\n"
2889 " font-family: '%s';\n"
2890 " font-size: %dpt;\n"
2891 " font-weight: %d;\n"
2892 " font-style: %s;\n"
2893 "}",
2894 pango_font_description_get_family (ms),
2895 pango_font_description_get_size (ms) / PANGO_SCALE,
2896 pango_font_description_get_weight (ms),
2897 styles[pango_font_description_get_style (ms)]);
2898
2899 context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
2900 gtk_style_context_get_style (
2901 context,
2902 "link-color", &link,
2903 "visited-link-color", &visited,
2904 NULL);
2905
2906 if (link == NULL) {
2907 link = g_slice_new0 (GdkColor);
2908 link->blue = G_MAXINT16;
2909 }
2910
2911 if (visited == NULL) {
2912 visited = g_slice_new0 (GdkColor);
2913 visited->red = G_MAXINT16;
2914 }
2915
2916 g_string_append_printf (
2917 stylesheet,
2918 "a {\n"
2919 " color: #%06x;\n"
2920 "}\n"
2921 "a:visited {\n"
2922 " color: #%06x;\n"
2923 "}\n",
2924 e_color_to_value (link),
2925 e_color_to_value (visited));
2926
2927 gdk_color_free (link);
2928 gdk_color_free (visited);
2929
2930 base64 = g_base64_encode ((guchar *) stylesheet->str, stylesheet->len);
2931 g_string_free (stylesheet, TRUE);
2932
2933 stylesheet = g_string_new ("data:text/css;charset=utf-8;base64,");
2934 g_string_append (stylesheet, base64);
2935 g_free (base64);
2936
2937 settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
2938 g_object_set (
2939 G_OBJECT (settings),
2940 "default-font-size", pango_font_description_get_size (vw) / PANGO_SCALE,
2941 "default-font-family", pango_font_description_get_family (vw),
2942 "monospace-font-family", pango_font_description_get_family (ms),
2943 "default-monospace-font-size", (pango_font_description_get_size (ms) / PANGO_SCALE),
2944 "minimum-font-size", (pango_font_description_get_size (min_size) / PANGO_SCALE),
2945 "user-stylesheet-uri", stylesheet->str,
2946 NULL);
2947
2948 g_string_free (stylesheet, TRUE);
2949
2950 pango_font_description_free (ms);
2951 pango_font_description_free (vw);
2952 }
2953
2954 void
2955 e_web_view_install_request_handler (EWebView *web_view,
2956 GType handler_type)
2957 {
2958 SoupSession *session;
2959 SoupSessionFeature *feature;
2960 gboolean new;
2961
2962 session = webkit_get_default_session ();
2963
2964 feature = soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
2965 new = FALSE;
2966 if (feature == NULL) {
2967 feature = SOUP_SESSION_FEATURE (soup_requester_new ());
2968 soup_session_add_feature (session, feature);
2969 new = TRUE;
2970 }
2971
2972 soup_session_feature_add_feature (feature, handler_type);
2973
2974 if (new) {
2975 g_object_unref (feature);
2976 }
2977 }