evolution-3.6.4/widgets/misc/e-web-view.c

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 }