No issues found
1 /*
2 * e-web-view-gtkhtml.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-gtkhtml.h"
24
25 #include <string.h>
26 #include <glib/gi18n-lib.h>
27
28 #include <camel/camel.h>
29 #include <libebackend/libebackend.h>
30
31 #include <e-util/e-util.h>
32 #include <e-util/e-plugin-ui.h>
33 #include <libevolution-utils/e-alert-dialog.h>
34 #include <libevolution-utils/e-alert-sink.h>
35
36 #include "e-popup-action.h"
37 #include "e-selectable.h"
38
39 #define E_WEB_VIEW_GTKHTML_GET_PRIVATE(obj) \
40 (G_TYPE_INSTANCE_GET_PRIVATE \
41 ((obj), E_TYPE_WEB_VIEW_GTKHTML, EWebViewGtkHTMLPrivate))
42
43 typedef struct _EWebViewGtkHTMLRequest EWebViewGtkHTMLRequest;
44
45 struct _EWebViewGtkHTMLPrivate {
46 GList *requests;
47 GtkUIManager *ui_manager;
48 gchar *selected_uri;
49 GdkPixbufAnimation *cursor_image;
50
51 GtkAction *open_proxy;
52 GtkAction *print_proxy;
53 GtkAction *save_as_proxy;
54
55 GtkTargetList *copy_target_list;
56 GtkTargetList *paste_target_list;
57
58 /* Lockdown Options */
59 guint disable_printing : 1;
60 guint disable_save_to_disk : 1;
61 };
62
63 struct _EWebViewGtkHTMLRequest {
64 GFile *file;
65 EWebViewGtkHTML *web_view;
66 GCancellable *cancellable;
67 GInputStream *input_stream;
68 GtkHTMLStream *output_stream;
69 gchar buffer[4096];
70 };
71
72 enum {
73 PROP_0,
74 PROP_ANIMATE,
75 PROP_CARET_MODE,
76 PROP_COPY_TARGET_LIST,
77 PROP_DISABLE_PRINTING,
78 PROP_DISABLE_SAVE_TO_DISK,
79 PROP_EDITABLE,
80 PROP_INLINE_SPELLING,
81 PROP_MAGIC_LINKS,
82 PROP_MAGIC_SMILEYS,
83 PROP_OPEN_PROXY,
84 PROP_PASTE_TARGET_LIST,
85 PROP_PRINT_PROXY,
86 PROP_SAVE_AS_PROXY,
87 PROP_SELECTED_URI,
88 PROP_CURSOR_IMAGE
89 };
90
91 enum {
92 COPY_CLIPBOARD,
93 CUT_CLIPBOARD,
94 PASTE_CLIPBOARD,
95 POPUP_EVENT,
96 STATUS_MESSAGE,
97 STOP_LOADING,
98 UPDATE_ACTIONS,
99 PROCESS_MAILTO,
100 LAST_SIGNAL
101 };
102
103 static guint signals[LAST_SIGNAL];
104
105 static const gchar *ui =
106 "<ui>"
107 " <popup name='context'>"
108 " <menuitem action='copy-clipboard'/>"
109 " <separator/>"
110 " <placeholder name='custom-actions-1'>"
111 " <menuitem action='open'/>"
112 " <menuitem action='save-as'/>"
113 " <menuitem action='http-open'/>"
114 " <menuitem action='send-message'/>"
115 " <menuitem action='print'/>"
116 " </placeholder>"
117 " <placeholder name='custom-actions-2'>"
118 " <menuitem action='uri-copy'/>"
119 " <menuitem action='mailto-copy'/>"
120 " <menuitem action='image-copy'/>"
121 " </placeholder>"
122 " <placeholder name='custom-actions-3'/>"
123 " <separator/>"
124 " <menuitem action='select-all'/>"
125 " </popup>"
126 "</ui>";
127
128 /* Forward Declarations */
129 static void e_web_view_gtkhtml_alert_sink_init (EAlertSinkInterface *interface);
130 static void e_web_view_gtkhtml_selectable_init (ESelectableInterface *interface);
131
132 G_DEFINE_TYPE_WITH_CODE (
133 EWebViewGtkHTML,
134 e_web_view_gtkhtml,
135 GTK_TYPE_HTML,
136 G_IMPLEMENT_INTERFACE (
137 E_TYPE_EXTENSIBLE, NULL)
138 G_IMPLEMENT_INTERFACE (
139 E_TYPE_ALERT_SINK,
140 e_web_view_gtkhtml_alert_sink_init)
141 G_IMPLEMENT_INTERFACE (
142 E_TYPE_SELECTABLE,
143 e_web_view_gtkhtml_selectable_init))
144
145 static EWebViewGtkHTMLRequest *
146 web_view_gtkhtml_request_new (EWebViewGtkHTML *web_view,
147 const gchar *uri,
148 GtkHTMLStream *stream)
149 {
150 EWebViewGtkHTMLRequest *request;
151 GList *list;
152
153 request = g_slice_new (EWebViewGtkHTMLRequest);
154
155 /* Try to detect file paths posing as URIs. */
156 if (*uri == '/')
157 request->file = g_file_new_for_path (uri);
158 else
159 request->file = g_file_new_for_uri (uri);
160
161 request->web_view = g_object_ref (web_view);
162 request->cancellable = g_cancellable_new ();
163 request->input_stream = NULL;
164 request->output_stream = stream;
165
166 list = request->web_view->priv->requests;
167 list = g_list_prepend (list, request);
168 request->web_view->priv->requests = list;
169
170 return request;
171 }
172
173 static void
174 web_view_gtkhtml_request_free (EWebViewGtkHTMLRequest *request)
175 {
176 GList *list;
177
178 list = request->web_view->priv->requests;
179 list = g_list_remove (list, request);
180 request->web_view->priv->requests = list;
181
182 g_object_unref (request->file);
183 g_object_unref (request->web_view);
184 g_object_unref (request->cancellable);
185
186 if (request->input_stream != NULL)
187 g_object_unref (request->input_stream);
188
189 g_slice_free (EWebViewGtkHTMLRequest, request);
190 }
191
192 static void
193 web_view_gtkhtml_request_cancel (EWebViewGtkHTMLRequest *request)
194 {
195 g_cancellable_cancel (request->cancellable);
196 }
197
198 static gboolean
199 web_view_gtkhtml_request_check_for_error (EWebViewGtkHTMLRequest *request,
200 GError *error)
201 {
202 GtkHTML *html;
203 GtkHTMLStream *stream;
204
205 if (error == NULL)
206 return FALSE;
207
208 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
209 /* use this error, but do not close the stream */
210 g_error_free (error);
211 return TRUE;
212 }
213
214 /* XXX Should we log errors that are not cancellations? */
215
216 html = GTK_HTML (request->web_view);
217 stream = request->output_stream;
218
219 gtk_html_end (html, stream, GTK_HTML_STREAM_ERROR);
220 web_view_gtkhtml_request_free (request);
221 g_error_free (error);
222
223 return TRUE;
224 }
225
226 static void
227 web_view_gtkhtml_request_stream_read_cb (GInputStream *input_stream,
228 GAsyncResult *result,
229 EWebViewGtkHTMLRequest *request)
230 {
231 gssize bytes_read;
232 GError *error = NULL;
233
234 bytes_read = g_input_stream_read_finish (input_stream, result, &error);
235
236 if (web_view_gtkhtml_request_check_for_error (request, error))
237 return;
238
239 if (bytes_read == 0) {
240 gtk_html_end (
241 GTK_HTML (request->web_view),
242 request->output_stream, GTK_HTML_STREAM_OK);
243 web_view_gtkhtml_request_free (request);
244 return;
245 }
246
247 gtk_html_write (
248 GTK_HTML (request->web_view),
249 request->output_stream, request->buffer, bytes_read);
250
251 g_input_stream_read_async (
252 request->input_stream, request->buffer,
253 sizeof (request->buffer), G_PRIORITY_DEFAULT,
254 request->cancellable, (GAsyncReadyCallback)
255 web_view_gtkhtml_request_stream_read_cb, request);
256 }
257
258 static void
259 web_view_gtkhtml_request_read_cb (GFile *file,
260 GAsyncResult *result,
261 EWebViewGtkHTMLRequest *request)
262 {
263 GFileInputStream *input_stream;
264 GError *error = NULL;
265
266 /* Input stream might be NULL, so don't use cast macro. */
267 input_stream = g_file_read_finish (file, result, &error);
268 request->input_stream = (GInputStream *) input_stream;
269
270 if (web_view_gtkhtml_request_check_for_error (request, error))
271 return;
272
273 g_input_stream_read_async (
274 request->input_stream, request->buffer,
275 sizeof (request->buffer), G_PRIORITY_DEFAULT,
276 request->cancellable, (GAsyncReadyCallback)
277 web_view_gtkhtml_request_stream_read_cb, request);
278 }
279
280 static void
281 action_copy_clipboard_cb (GtkAction *action,
282 EWebViewGtkHTML *web_view)
283 {
284 e_web_view_gtkhtml_copy_clipboard (web_view);
285 }
286
287 static void
288 action_http_open_cb (GtkAction *action,
289 EWebViewGtkHTML *web_view)
290 {
291 const gchar *uri;
292 gpointer parent;
293
294 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
295 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
296
297 uri = e_web_view_gtkhtml_get_selected_uri (web_view);
298 g_return_if_fail (uri != NULL);
299
300 e_show_uri (parent, uri);
301 }
302
303 static void
304 action_mailto_copy_cb (GtkAction *action,
305 EWebViewGtkHTML *web_view)
306 {
307 CamelURL *curl;
308 CamelInternetAddress *inet_addr;
309 GtkClipboard *clipboard;
310 const gchar *uri;
311 gchar *text;
312
313 uri = e_web_view_gtkhtml_get_selected_uri (web_view);
314 g_return_if_fail (uri != NULL);
315
316 /* This should work because we checked it in update_actions(). */
317 curl = camel_url_new (uri, NULL);
318 g_return_if_fail (curl != NULL);
319
320 inet_addr = camel_internet_address_new ();
321 camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path);
322 text = camel_address_format (CAMEL_ADDRESS (inet_addr));
323 if (text == NULL || *text == '\0')
324 text = g_strdup (uri + strlen ("mailto:"));
325
326 g_object_unref (inet_addr);
327 camel_url_free (curl);
328
329 clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
330 gtk_clipboard_set_text (clipboard, text, -1);
331 gtk_clipboard_store (clipboard);
332
333 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
334 gtk_clipboard_set_text (clipboard, text, -1);
335 gtk_clipboard_store (clipboard);
336
337 g_free (text);
338 }
339
340 static void
341 action_select_all_cb (GtkAction *action,
342 EWebViewGtkHTML *web_view)
343 {
344 e_web_view_gtkhtml_select_all (web_view);
345 }
346
347 static void
348 action_send_message_cb (GtkAction *action,
349 EWebViewGtkHTML *web_view)
350 {
351 const gchar *uri;
352 gpointer parent;
353 gboolean handled;
354
355 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
356 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
357
358 uri = e_web_view_gtkhtml_get_selected_uri (web_view);
359 g_return_if_fail (uri != NULL);
360
361 handled = FALSE;
362 g_signal_emit (web_view, signals[PROCESS_MAILTO], 0, uri, &handled);
363
364 if (!handled)
365 e_show_uri (parent, uri);
366 }
367
368 static void
369 action_uri_copy_cb (GtkAction *action,
370 EWebViewGtkHTML *web_view)
371 {
372 GtkClipboard *clipboard;
373 const gchar *uri;
374
375 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
376 uri = e_web_view_gtkhtml_get_selected_uri (web_view);
377 g_return_if_fail (uri != NULL);
378
379 gtk_clipboard_set_text (clipboard, uri, -1);
380 gtk_clipboard_store (clipboard);
381 }
382
383 static void
384 action_image_copy_cb (GtkAction *action,
385 EWebViewGtkHTML *web_view)
386 {
387 GtkClipboard *clipboard;
388 GdkPixbufAnimation *animation;
389 GdkPixbuf *pixbuf;
390
391 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
392 animation = e_web_view_gtkhtml_get_cursor_image (web_view);
393 g_return_if_fail (animation != NULL);
394
395 pixbuf = gdk_pixbuf_animation_get_static_image (animation);
396 if (!pixbuf)
397 return;
398
399 gtk_clipboard_set_image (clipboard, pixbuf);
400 gtk_clipboard_store (clipboard);
401 }
402
403 static GtkActionEntry uri_entries[] = {
404
405 { "uri-copy",
406 GTK_STOCK_COPY,
407 N_("_Copy Link Location"),
408 NULL,
409 N_("Copy the link to the clipboard"),
410 G_CALLBACK (action_uri_copy_cb) }
411 };
412
413 static GtkActionEntry http_entries[] = {
414
415 { "http-open",
416 "emblem-web",
417 N_("_Open Link in Browser"),
418 NULL,
419 N_("Open the link in a web browser"),
420 G_CALLBACK (action_http_open_cb) }
421 };
422
423 static GtkActionEntry mailto_entries[] = {
424
425 { "mailto-copy",
426 GTK_STOCK_COPY,
427 N_("_Copy Email Address"),
428 NULL,
429 N_("Copy the email address to the clipboard"),
430 G_CALLBACK (action_mailto_copy_cb) },
431
432 { "send-message",
433 "mail-message-new",
434 N_("_Send New Message To..."),
435 NULL,
436 N_("Send a mail message to this address"),
437 G_CALLBACK (action_send_message_cb) }
438 };
439
440 static GtkActionEntry image_entries[] = {
441
442 { "image-copy",
443 GTK_STOCK_COPY,
444 N_("_Copy Image"),
445 NULL,
446 N_("Copy the image to the clipboard"),
447 G_CALLBACK (action_image_copy_cb) }
448 };
449
450 static GtkActionEntry selection_entries[] = {
451
452 { "copy-clipboard",
453 GTK_STOCK_COPY,
454 NULL,
455 NULL,
456 N_("Copy the selection"),
457 G_CALLBACK (action_copy_clipboard_cb) },
458 };
459
460 static GtkActionEntry standard_entries[] = {
461
462 { "select-all",
463 GTK_STOCK_SELECT_ALL,
464 NULL,
465 NULL,
466 N_("Select all text and images"),
467 G_CALLBACK (action_select_all_cb) }
468 };
469
470 static gboolean
471 web_view_gtkhtml_button_press_event_cb (EWebViewGtkHTML *web_view,
472 GdkEventButton *event,
473 GtkHTML *frame)
474 {
475 gboolean event_handled = FALSE;
476 gchar *uri = NULL;
477
478 if (event) {
479 GdkPixbufAnimation *anim;
480
481 if (frame == NULL)
482 frame = GTK_HTML (web_view);
483
484 anim = gtk_html_get_image_at (frame, event->x, event->y);
485 e_web_view_gtkhtml_set_cursor_image (web_view, anim);
486 if (anim != NULL)
487 g_object_unref (anim);
488 }
489
490 if (event != NULL && event->button != 3)
491 return FALSE;
492
493 /* Only extract a URI if no selection is active. Selected text
494 * implies the user is more likely to want to copy the selection
495 * to the clipboard than open a link within the selection. */
496 if (!e_web_view_gtkhtml_is_selection_active (web_view))
497 uri = e_web_view_gtkhtml_extract_uri (web_view, event, frame);
498
499 if (uri != NULL && g_str_has_prefix (uri, "##")) {
500 g_free (uri);
501 return FALSE;
502 }
503
504 g_signal_emit (
505 web_view, signals[POPUP_EVENT], 0,
506 event, uri, &event_handled);
507
508 g_free (uri);
509
510 return event_handled;
511 }
512
513 static void
514 web_view_gtkhtml_menu_item_select_cb (EWebViewGtkHTML *web_view,
515 GtkWidget *widget)
516 {
517 GtkAction *action;
518 GtkActivatable *activatable;
519 const gchar *tooltip;
520
521 activatable = GTK_ACTIVATABLE (widget);
522 action = gtk_activatable_get_related_action (activatable);
523 tooltip = gtk_action_get_tooltip (action);
524
525 if (tooltip == NULL)
526 return;
527
528 e_web_view_gtkhtml_status_message (web_view, tooltip);
529 }
530
531 static void
532 web_view_gtkhtml_menu_item_deselect_cb (EWebViewGtkHTML *web_view)
533 {
534 e_web_view_gtkhtml_status_message (web_view, NULL);
535 }
536
537 static void
538 web_view_gtkhtml_connect_proxy_cb (EWebViewGtkHTML *web_view,
539 GtkAction *action,
540 GtkWidget *proxy)
541 {
542 if (!GTK_IS_MENU_ITEM (proxy))
543 return;
544
545 g_signal_connect_swapped (
546 proxy, "select",
547 G_CALLBACK (web_view_gtkhtml_menu_item_select_cb), web_view);
548
549 g_signal_connect_swapped (
550 proxy, "deselect",
551 G_CALLBACK (web_view_gtkhtml_menu_item_deselect_cb), web_view);
552 }
553
554 static void
555 web_view_gtkhtml_set_property (GObject *object,
556 guint property_id,
557 const GValue *value,
558 GParamSpec *pspec)
559 {
560 switch (property_id) {
561 case PROP_ANIMATE:
562 e_web_view_gtkhtml_set_animate (
563 E_WEB_VIEW_GTKHTML (object),
564 g_value_get_boolean (value));
565 return;
566
567 case PROP_CARET_MODE:
568 e_web_view_gtkhtml_set_caret_mode (
569 E_WEB_VIEW_GTKHTML (object),
570 g_value_get_boolean (value));
571 return;
572
573 case PROP_DISABLE_PRINTING:
574 e_web_view_gtkhtml_set_disable_printing (
575 E_WEB_VIEW_GTKHTML (object),
576 g_value_get_boolean (value));
577 return;
578
579 case PROP_DISABLE_SAVE_TO_DISK:
580 e_web_view_gtkhtml_set_disable_save_to_disk (
581 E_WEB_VIEW_GTKHTML (object),
582 g_value_get_boolean (value));
583 return;
584
585 case PROP_EDITABLE:
586 e_web_view_gtkhtml_set_editable (
587 E_WEB_VIEW_GTKHTML (object),
588 g_value_get_boolean (value));
589 return;
590
591 case PROP_INLINE_SPELLING:
592 e_web_view_gtkhtml_set_inline_spelling (
593 E_WEB_VIEW_GTKHTML (object),
594 g_value_get_boolean (value));
595 return;
596
597 case PROP_MAGIC_LINKS:
598 e_web_view_gtkhtml_set_magic_links (
599 E_WEB_VIEW_GTKHTML (object),
600 g_value_get_boolean (value));
601 return;
602
603 case PROP_MAGIC_SMILEYS:
604 e_web_view_gtkhtml_set_magic_smileys (
605 E_WEB_VIEW_GTKHTML (object),
606 g_value_get_boolean (value));
607 return;
608
609 case PROP_OPEN_PROXY:
610 e_web_view_gtkhtml_set_open_proxy (
611 E_WEB_VIEW_GTKHTML (object),
612 g_value_get_object (value));
613 return;
614
615 case PROP_PRINT_PROXY:
616 e_web_view_gtkhtml_set_print_proxy (
617 E_WEB_VIEW_GTKHTML (object),
618 g_value_get_object (value));
619 return;
620
621 case PROP_SAVE_AS_PROXY:
622 e_web_view_gtkhtml_set_save_as_proxy (
623 E_WEB_VIEW_GTKHTML (object),
624 g_value_get_object (value));
625 return;
626
627 case PROP_SELECTED_URI:
628 e_web_view_gtkhtml_set_selected_uri (
629 E_WEB_VIEW_GTKHTML (object),
630 g_value_get_string (value));
631 return;
632 case PROP_CURSOR_IMAGE:
633 e_web_view_gtkhtml_set_cursor_image (
634 E_WEB_VIEW_GTKHTML (object),
635 g_value_get_object (value));
636 return;
637 }
638
639 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
640 }
641
642 static void
643 web_view_gtkhtml_get_property (GObject *object,
644 guint property_id,
645 GValue *value,
646 GParamSpec *pspec)
647 {
648 switch (property_id) {
649 case PROP_ANIMATE:
650 g_value_set_boolean (
651 value, e_web_view_gtkhtml_get_animate (
652 E_WEB_VIEW_GTKHTML (object)));
653 return;
654
655 case PROP_CARET_MODE:
656 g_value_set_boolean (
657 value, e_web_view_gtkhtml_get_caret_mode (
658 E_WEB_VIEW_GTKHTML (object)));
659 return;
660
661 case PROP_COPY_TARGET_LIST:
662 g_value_set_boxed (
663 value, e_web_view_gtkhtml_get_copy_target_list (
664 E_WEB_VIEW_GTKHTML (object)));
665 return;
666
667 case PROP_DISABLE_PRINTING:
668 g_value_set_boolean (
669 value, e_web_view_gtkhtml_get_disable_printing (
670 E_WEB_VIEW_GTKHTML (object)));
671 return;
672
673 case PROP_DISABLE_SAVE_TO_DISK:
674 g_value_set_boolean (
675 value, e_web_view_gtkhtml_get_disable_save_to_disk (
676 E_WEB_VIEW_GTKHTML (object)));
677 return;
678
679 case PROP_EDITABLE:
680 g_value_set_boolean (
681 value, e_web_view_gtkhtml_get_editable (
682 E_WEB_VIEW_GTKHTML (object)));
683 return;
684
685 case PROP_INLINE_SPELLING:
686 g_value_set_boolean (
687 value, e_web_view_gtkhtml_get_inline_spelling (
688 E_WEB_VIEW_GTKHTML (object)));
689 return;
690
691 case PROP_MAGIC_LINKS:
692 g_value_set_boolean (
693 value, e_web_view_gtkhtml_get_magic_links (
694 E_WEB_VIEW_GTKHTML (object)));
695 return;
696
697 case PROP_MAGIC_SMILEYS:
698 g_value_set_boolean (
699 value, e_web_view_gtkhtml_get_magic_smileys (
700 E_WEB_VIEW_GTKHTML (object)));
701 return;
702
703 case PROP_OPEN_PROXY:
704 g_value_set_object (
705 value, e_web_view_gtkhtml_get_open_proxy (
706 E_WEB_VIEW_GTKHTML (object)));
707 return;
708
709 case PROP_PASTE_TARGET_LIST:
710 g_value_set_boxed (
711 value, e_web_view_gtkhtml_get_paste_target_list (
712 E_WEB_VIEW_GTKHTML (object)));
713 return;
714
715 case PROP_PRINT_PROXY:
716 g_value_set_object (
717 value, e_web_view_gtkhtml_get_print_proxy (
718 E_WEB_VIEW_GTKHTML (object)));
719 return;
720
721 case PROP_SAVE_AS_PROXY:
722 g_value_set_object (
723 value, e_web_view_gtkhtml_get_save_as_proxy (
724 E_WEB_VIEW_GTKHTML (object)));
725 return;
726
727 case PROP_SELECTED_URI:
728 g_value_set_string (
729 value, e_web_view_gtkhtml_get_selected_uri (
730 E_WEB_VIEW_GTKHTML (object)));
731 return;
732
733 case PROP_CURSOR_IMAGE:
734 g_value_set_object (
735 value, e_web_view_gtkhtml_get_cursor_image (
736 E_WEB_VIEW_GTKHTML (object)));
737 return;
738 }
739
740 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
741 }
742
743 static void
744 web_view_gtkhtml_dispose (GObject *object)
745 {
746 EWebViewGtkHTMLPrivate *priv;
747
748 priv = E_WEB_VIEW_GTKHTML_GET_PRIVATE (object);
749
750 if (priv->ui_manager != NULL) {
751 g_object_unref (priv->ui_manager);
752 priv->ui_manager = NULL;
753 }
754
755 if (priv->open_proxy != NULL) {
756 g_object_unref (priv->open_proxy);
757 priv->open_proxy = NULL;
758 }
759
760 if (priv->print_proxy != NULL) {
761 g_object_unref (priv->print_proxy);
762 priv->print_proxy = NULL;
763 }
764
765 if (priv->save_as_proxy != NULL) {
766 g_object_unref (priv->save_as_proxy);
767 priv->save_as_proxy = NULL;
768 }
769
770 if (priv->copy_target_list != NULL) {
771 gtk_target_list_unref (priv->copy_target_list);
772 priv->copy_target_list = NULL;
773 }
774
775 if (priv->paste_target_list != NULL) {
776 gtk_target_list_unref (priv->paste_target_list);
777 priv->paste_target_list = NULL;
778 }
779
780 if (priv->cursor_image != NULL) {
781 g_object_unref (priv->cursor_image);
782 priv->cursor_image = NULL;
783 }
784
785 /* Chain up to parent's dispose() method. */
786 G_OBJECT_CLASS (e_web_view_gtkhtml_parent_class)->dispose (object);
787 }
788
789 static void
790 web_view_gtkhtml_finalize (GObject *object)
791 {
792 EWebViewGtkHTMLPrivate *priv;
793
794 priv = E_WEB_VIEW_GTKHTML_GET_PRIVATE (object);
795
796 /* All URI requests should be complete or cancelled by now. */
797 if (priv->requests != NULL)
798 g_warning ("Finalizing EWebViewGtkHTML with active URI requests");
799
800 g_free (priv->selected_uri);
801
802 /* Chain up to parent's finalize() method. */
803 G_OBJECT_CLASS (e_web_view_gtkhtml_parent_class)->finalize (object);
804 }
805
806 static void
807 web_view_gtkhtml_constructed (GObject *object)
808 {
809 #ifndef G_OS_WIN32
810 GSettings *settings;
811
812 settings = g_settings_new ("org.gnome.desktop.lockdown");
813
814 g_settings_bind (
815 settings, "disable-printing",
816 object, "disable-printing",
817 G_SETTINGS_BIND_GET);
818
819 g_settings_bind (
820 settings, "disable-save-to-disk",
821 object, "disable-save-to-disk",
822 G_SETTINGS_BIND_GET);
823
824 g_object_unref (settings);
825 #endif
826
827 /* Chain up to parent's constructed() method. */
828 G_OBJECT_CLASS (e_web_view_gtkhtml_parent_class)->constructed (object);
829 }
830
831 static gboolean
832 web_view_gtkhtml_button_press_event (GtkWidget *widget,
833 GdkEventButton *event)
834 {
835 GtkWidgetClass *widget_class;
836 EWebViewGtkHTML *web_view;
837
838 web_view = E_WEB_VIEW_GTKHTML (widget);
839
840 if (web_view_gtkhtml_button_press_event_cb (web_view, event, NULL))
841 return TRUE;
842
843 /* Chain up to parent's button_press_event() method. */
844 widget_class = GTK_WIDGET_CLASS (e_web_view_gtkhtml_parent_class);
845 return widget_class->button_press_event (widget, event);
846 }
847
848 static gboolean
849 web_view_gtkhtml_scroll_event (GtkWidget *widget,
850 GdkEventScroll *event)
851 {
852 if (event->state & GDK_CONTROL_MASK) {
853 GdkScrollDirection direction = event->direction;
854
855 #if GTK_CHECK_VERSION(3,3,18)
856 if (direction == GDK_SCROLL_SMOOTH) {
857 static gdouble total_delta_y = 0.0;
858
859 total_delta_y += event->delta_y;
860
861 if (total_delta_y >= 1.0) {
862 total_delta_y = 0.0;
863 direction = GDK_SCROLL_DOWN;
864 } else if (total_delta_y <= -1.0) {
865 total_delta_y = 0.0;
866 direction = GDK_SCROLL_UP;
867 } else {
868 return FALSE;
869 }
870 }
871 #endif
872
873 switch (direction) {
874 case GDK_SCROLL_UP:
875 gtk_html_zoom_in (GTK_HTML (widget));
876 return TRUE;
877 case GDK_SCROLL_DOWN:
878 gtk_html_zoom_out (GTK_HTML (widget));
879 return TRUE;
880 default:
881 break;
882 }
883 }
884
885 return FALSE;
886 }
887
888 static void
889 web_view_gtkhtml_url_requested (GtkHTML *html,
890 const gchar *uri,
891 GtkHTMLStream *stream)
892 {
893 EWebViewGtkHTMLRequest *request;
894
895 request = web_view_gtkhtml_request_new (E_WEB_VIEW_GTKHTML (html), uri, stream);
896
897 g_file_read_async (
898 request->file, G_PRIORITY_DEFAULT,
899 request->cancellable, (GAsyncReadyCallback)
900 web_view_gtkhtml_request_read_cb, request);
901 }
902
903 static void
904 web_view_gtkhtml_gtkhtml_link_clicked (GtkHTML *html,
905 const gchar *uri)
906 {
907 EWebViewGtkHTMLClass *class;
908 EWebViewGtkHTML *web_view;
909
910 web_view = E_WEB_VIEW_GTKHTML (html);
911
912 class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
913 g_return_if_fail (class->link_clicked != NULL);
914
915 class->link_clicked (web_view, uri);
916 }
917
918 static void
919 web_view_gtkhtml_on_url (GtkHTML *html,
920 const gchar *uri)
921 {
922 EWebViewGtkHTMLClass *class;
923 EWebViewGtkHTML *web_view;
924
925 web_view = E_WEB_VIEW_GTKHTML (html);
926
927 class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
928 g_return_if_fail (class->hovering_over_link != NULL);
929
930 /* XXX WebKit would supply a title here. */
931 class->hovering_over_link (web_view, NULL, uri);
932 }
933
934 static void
935 web_view_gtkhtml_iframe_created (GtkHTML *html,
936 GtkHTML *iframe)
937 {
938 g_signal_connect_swapped (
939 iframe, "button-press-event",
940 G_CALLBACK (web_view_gtkhtml_button_press_event_cb), html);
941 }
942
943 static gchar *
944 web_view_gtkhtml_extract_uri (EWebViewGtkHTML *web_view,
945 GdkEventButton *event,
946 GtkHTML *html)
947 {
948 gchar *uri;
949
950 if (event != NULL)
951 uri = gtk_html_get_url_at (html, event->x, event->y);
952 else
953 uri = gtk_html_get_cursor_url (html);
954
955 return uri;
956 }
957
958 static void
959 web_view_gtkhtml_hovering_over_link (EWebViewGtkHTML *web_view,
960 const gchar *title,
961 const gchar *uri)
962 {
963 CamelInternetAddress *address;
964 CamelURL *curl;
965 const gchar *format = NULL;
966 gchar *message = NULL;
967 gchar *who;
968
969 if (uri == NULL || *uri == '\0')
970 goto exit;
971
972 if (g_str_has_prefix (uri, "mailto:"))
973 format = _("Click to mail %s");
974 else if (g_str_has_prefix (uri, "callto:"))
975 format = _("Click to call %s");
976 else if (g_str_has_prefix (uri, "h323:"))
977 format = _("Click to call %s");
978 else if (g_str_has_prefix (uri, "sip:"))
979 format = _("Click to call %s");
980 else if (g_str_has_prefix (uri, "##"))
981 message = g_strdup (_("Click to hide/unhide addresses"));
982 else
983 message = g_strdup_printf (_("Click to open %s"), uri);
984
985 if (format == NULL)
986 goto exit;
987
988 /* XXX Use something other than Camel here. Surely
989 * there's other APIs around that can do this. */
990 curl = camel_url_new (uri, NULL);
991 address = camel_internet_address_new ();
992 camel_address_decode (CAMEL_ADDRESS (address), curl->path);
993 who = camel_address_format (CAMEL_ADDRESS (address));
994 g_object_unref (address);
995 camel_url_free (curl);
996
997 if (who == NULL)
998 who = g_strdup (strchr (uri, ':') + 1);
999
1000 message = g_strdup_printf (format, who);
1001
1002 g_free (who);
1003
1004 exit:
1005 e_web_view_gtkhtml_status_message (web_view, message);
1006
1007 g_free (message);
1008 }
1009
1010 static void
1011 web_view_gtkhtml_link_clicked (EWebViewGtkHTML *web_view,
1012 const gchar *uri)
1013 {
1014 gpointer parent;
1015
1016 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
1017 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
1018
1019 e_show_uri (parent, uri);
1020 }
1021
1022 static void
1023 web_view_gtkhtml_load_string (EWebViewGtkHTML *web_view,
1024 const gchar *string)
1025 {
1026 if (string != NULL && *string != '\0')
1027 gtk_html_load_from_string (GTK_HTML (web_view), string, -1);
1028 else
1029 e_web_view_gtkhtml_clear (web_view);
1030 }
1031
1032 static void
1033 web_view_gtkhtml_copy_clipboard (EWebViewGtkHTML *web_view)
1034 {
1035 gtk_html_command (GTK_HTML (web_view), "copy");
1036 }
1037
1038 static void
1039 web_view_gtkhtml_cut_clipboard (EWebViewGtkHTML *web_view)
1040 {
1041 if (e_web_view_gtkhtml_get_editable (web_view))
1042 gtk_html_command (GTK_HTML (web_view), "cut");
1043 }
1044
1045 static void
1046 web_view_gtkhtml_paste_clipboard (EWebViewGtkHTML *web_view)
1047 {
1048 if (e_web_view_gtkhtml_get_editable (web_view))
1049 gtk_html_command (GTK_HTML (web_view), "paste");
1050 }
1051
1052 static gboolean
1053 web_view_gtkhtml_popup_event (EWebViewGtkHTML *web_view,
1054 GdkEventButton *event,
1055 const gchar *uri)
1056 {
1057 e_web_view_gtkhtml_set_selected_uri (web_view, uri);
1058 e_web_view_gtkhtml_show_popup_menu (web_view, event, NULL, NULL);
1059
1060 return TRUE;
1061 }
1062
1063 static void
1064 web_view_gtkhtml_stop_loading (EWebViewGtkHTML *web_view)
1065 {
1066 g_list_foreach (
1067 web_view->priv->requests, (GFunc)
1068 web_view_gtkhtml_request_cancel, NULL);
1069
1070 gtk_html_stop (GTK_HTML (web_view));
1071 }
1072
1073 static void
1074 web_view_gtkhtml_update_actions (EWebViewGtkHTML *web_view)
1075 {
1076 GtkActionGroup *action_group;
1077 gboolean have_selection;
1078 gboolean scheme_is_http = FALSE;
1079 gboolean scheme_is_mailto = FALSE;
1080 gboolean uri_is_valid = FALSE;
1081 gboolean has_cursor_image;
1082 gboolean visible;
1083 const gchar *group_name;
1084 const gchar *uri;
1085
1086 uri = e_web_view_gtkhtml_get_selected_uri (web_view);
1087 have_selection = e_web_view_gtkhtml_is_selection_active (web_view);
1088 has_cursor_image = e_web_view_gtkhtml_get_cursor_image (web_view) != NULL;
1089
1090 /* Parse the URI early so we know if the actions will work. */
1091 if (uri != NULL) {
1092 CamelURL *curl;
1093
1094 curl = camel_url_new (uri, NULL);
1095 uri_is_valid = (curl != NULL);
1096 camel_url_free (curl);
1097
1098 scheme_is_http =
1099 (g_ascii_strncasecmp (uri, "http:", 5) == 0) ||
1100 (g_ascii_strncasecmp (uri, "https:", 6) == 0);
1101
1102 scheme_is_mailto =
1103 (g_ascii_strncasecmp (uri, "mailto:", 7) == 0);
1104 }
1105
1106 /* Allow copying the URI even if it's malformed. */
1107 group_name = "uri";
1108 visible = (uri != NULL) && !scheme_is_mailto;
1109 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1110 gtk_action_group_set_visible (action_group, visible);
1111
1112 group_name = "http";
1113 visible = uri_is_valid && scheme_is_http;
1114 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1115 gtk_action_group_set_visible (action_group, visible);
1116
1117 group_name = "mailto";
1118 visible = uri_is_valid && scheme_is_mailto;
1119 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1120 gtk_action_group_set_visible (action_group, visible);
1121
1122 group_name = "image";
1123 visible = has_cursor_image;
1124 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1125 gtk_action_group_set_visible (action_group, visible);
1126
1127 group_name = "selection";
1128 visible = have_selection;
1129 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1130 gtk_action_group_set_visible (action_group, visible);
1131
1132 group_name = "standard";
1133 visible = (uri == NULL);
1134 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1135 gtk_action_group_set_visible (action_group, visible);
1136
1137 group_name = "lockdown-printing";
1138 visible = (uri == NULL) && !web_view->priv->disable_printing;
1139 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1140 gtk_action_group_set_visible (action_group, visible);
1141
1142 group_name = "lockdown-save-to-disk";
1143 visible = (uri == NULL) && !web_view->priv->disable_save_to_disk;
1144 action_group = e_web_view_gtkhtml_get_action_group (web_view, group_name);
1145 gtk_action_group_set_visible (action_group, visible);
1146 }
1147
1148 static void
1149 web_view_gtkhtml_submit_alert (EAlertSink *alert_sink,
1150 EAlert *alert)
1151 {
1152 GtkIconInfo *icon_info;
1153 EWebViewGtkHTML *web_view;
1154 GtkWidget *dialog;
1155 GString *buffer;
1156 const gchar *icon_name = NULL;
1157 const gchar *filename;
1158 gpointer parent;
1159 gchar *icon_uri;
1160 gint size = 0;
1161 GError *error = NULL;
1162
1163 web_view = E_WEB_VIEW_GTKHTML (alert_sink);
1164
1165 parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
1166 parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
1167
1168 /* We use equivalent named icons instead of stock IDs,
1169 * since it's easier to get the filename of the icon. */
1170 switch (e_alert_get_message_type (alert)) {
1171 case GTK_MESSAGE_INFO:
1172 icon_name = "dialog-information";
1173 break;
1174
1175 case GTK_MESSAGE_WARNING:
1176 icon_name = "dialog-warning";
1177 break;
1178
1179 case GTK_MESSAGE_ERROR:
1180 icon_name = "dialog-error";
1181 break;
1182
1183 default:
1184 dialog = e_alert_dialog_new (parent, alert);
1185 gtk_dialog_run (GTK_DIALOG (dialog));
1186 gtk_widget_destroy (dialog);
1187 return;
1188 }
1189
1190 gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &size, NULL);
1191
1192 icon_info = gtk_icon_theme_lookup_icon (
1193 gtk_icon_theme_get_default (),
1194 icon_name, size, GTK_ICON_LOOKUP_NO_SVG);
1195 g_return_if_fail (icon_info != NULL);
1196
1197 filename = gtk_icon_info_get_filename (icon_info);
1198 icon_uri = g_filename_to_uri (filename, NULL, &error);
1199
1200 if (error != NULL) {
1201 g_warning ("%s", error->message);
1202 g_clear_error (&error);
1203 }
1204
1205 buffer = g_string_sized_new (512);
1206
1207 g_string_append (
1208 buffer,
1209 "<html>"
1210 "<head>"
1211 "<meta http-equiv=\"content-type\""
1212 " content=\"text/html; charset=utf-8\">"
1213 "</head>"
1214 "<body>");
1215
1216 g_string_append (
1217 buffer,
1218 "<table bgcolor='#000000' width='100%'"
1219 " cellpadding='1' cellspacing='0'>"
1220 "<tr>"
1221 "<td>"
1222 "<table bgcolor='#dddddd' width='100%' cellpadding='6'>"
1223 "<tr>");
1224
1225 g_string_append_printf (
1226 buffer,
1227 "<tr>"
1228 "<td valign='top'>"
1229 "<img src='%s'/>"
1230 "</td>"
1231 "<td align='left' width='100%%'>"
1232 "<h3>%s</h3>"
1233 "%s"
1234 "</td>"
1235 "</tr>",
1236 icon_uri,
1237 e_alert_get_primary_text (alert),
1238 e_alert_get_secondary_text (alert));
1239
1240 g_string_append (
1241 buffer,
1242 "</table>"
1243 "</td>"
1244 "</tr>"
1245 "</table>"
1246 "</body>"
1247 "</html>");
1248
1249 e_web_view_gtkhtml_load_string (web_view, buffer->str);
1250
1251 g_string_free (buffer, TRUE);
1252
1253 gtk_icon_info_free (icon_info);
1254 g_free (icon_uri);
1255 }
1256
1257 static void
1258 web_view_gtkhtml_selectable_update_actions (ESelectable *selectable,
1259 EFocusTracker *focus_tracker,
1260 GdkAtom *clipboard_targets,
1261 gint n_clipboard_targets)
1262 {
1263 EWebViewGtkHTML *web_view;
1264 GtkAction *action;
1265 /*GtkTargetList *target_list;*/
1266 gboolean can_paste = FALSE;
1267 gboolean editable;
1268 gboolean have_selection;
1269 gboolean sensitive;
1270 const gchar *tooltip;
1271 /*gint ii;*/
1272
1273 web_view = E_WEB_VIEW_GTKHTML (selectable);
1274 editable = e_web_view_gtkhtml_get_editable (web_view);
1275 have_selection = e_web_view_gtkhtml_is_selection_active (web_view);
1276
1277 /* XXX GtkHtml implements its own clipboard instead of using
1278 * GDK_SELECTION_CLIPBOARD, so we don't get notifications
1279 * when the clipboard contents change. The logic below
1280 * is what we would do if GtkHtml worked properly.
1281 * Instead, we need to keep the Paste action sensitive so
1282 * its accelerator overrides GtkHtml's key binding. */
1283 #if 0
1284 target_list = e_selectable_get_paste_target_list (selectable);
1285 for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++)
1286 can_paste = gtk_target_list_find (
1287 target_list, clipboard_targets[ii], NULL);
1288 #endif
1289 can_paste = TRUE;
1290
1291 action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
1292 sensitive = editable && have_selection;
1293 tooltip = _("Cut the selection");
1294 gtk_action_set_sensitive (action, sensitive);
1295 gtk_action_set_tooltip (action, tooltip);
1296
1297 action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
1298 sensitive = have_selection;
1299 tooltip = _("Copy the selection");
1300 gtk_action_set_sensitive (action, sensitive);
1301 gtk_action_set_tooltip (action, tooltip);
1302
1303 action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
1304 sensitive = editable && can_paste;
1305 tooltip = _("Paste the clipboard");
1306 gtk_action_set_sensitive (action, sensitive);
1307 gtk_action_set_tooltip (action, tooltip);
1308
1309 action = e_focus_tracker_get_select_all_action (focus_tracker);
1310 sensitive = TRUE;
1311 tooltip = _("Select all text and images");
1312 gtk_action_set_sensitive (action, sensitive);
1313 gtk_action_set_tooltip (action, tooltip);
1314 }
1315
1316 static void
1317 web_view_gtkhtml_selectable_cut_clipboard (ESelectable *selectable)
1318 {
1319 e_web_view_gtkhtml_cut_clipboard (E_WEB_VIEW_GTKHTML (selectable));
1320 }
1321
1322 static void
1323 web_view_gtkhtml_selectable_copy_clipboard (ESelectable *selectable)
1324 {
1325 e_web_view_gtkhtml_copy_clipboard (E_WEB_VIEW_GTKHTML (selectable));
1326 }
1327
1328 static void
1329 web_view_gtkhtml_selectable_paste_clipboard (ESelectable *selectable)
1330 {
1331 e_web_view_gtkhtml_paste_clipboard (E_WEB_VIEW_GTKHTML (selectable));
1332 }
1333
1334 static void
1335 web_view_gtkhtml_selectable_select_all (ESelectable *selectable)
1336 {
1337 e_web_view_gtkhtml_select_all (E_WEB_VIEW_GTKHTML (selectable));
1338 }
1339
1340 static void
1341 e_web_view_gtkhtml_class_init (EWebViewGtkHTMLClass *class)
1342 {
1343 GObjectClass *object_class;
1344 GtkWidgetClass *widget_class;
1345 GtkHTMLClass *html_class;
1346
1347 g_type_class_add_private (class, sizeof (EWebViewGtkHTMLPrivate));
1348
1349 object_class = G_OBJECT_CLASS (class);
1350 object_class->set_property = web_view_gtkhtml_set_property;
1351 object_class->get_property = web_view_gtkhtml_get_property;
1352 object_class->dispose = web_view_gtkhtml_dispose;
1353 object_class->finalize = web_view_gtkhtml_finalize;
1354 object_class->constructed = web_view_gtkhtml_constructed;
1355
1356 widget_class = GTK_WIDGET_CLASS (class);
1357 widget_class->button_press_event = web_view_gtkhtml_button_press_event;
1358 widget_class->scroll_event = web_view_gtkhtml_scroll_event;
1359
1360 html_class = GTK_HTML_CLASS (class);
1361 html_class->url_requested = web_view_gtkhtml_url_requested;
1362 html_class->link_clicked = web_view_gtkhtml_gtkhtml_link_clicked;
1363 html_class->on_url = web_view_gtkhtml_on_url;
1364 html_class->iframe_created = web_view_gtkhtml_iframe_created;
1365
1366 class->extract_uri = web_view_gtkhtml_extract_uri;
1367 class->hovering_over_link = web_view_gtkhtml_hovering_over_link;
1368 class->link_clicked = web_view_gtkhtml_link_clicked;
1369 class->load_string = web_view_gtkhtml_load_string;
1370 class->copy_clipboard = web_view_gtkhtml_copy_clipboard;
1371 class->cut_clipboard = web_view_gtkhtml_cut_clipboard;
1372 class->paste_clipboard = web_view_gtkhtml_paste_clipboard;
1373 class->popup_event = web_view_gtkhtml_popup_event;
1374 class->stop_loading = web_view_gtkhtml_stop_loading;
1375 class->update_actions = web_view_gtkhtml_update_actions;
1376
1377 g_object_class_install_property (
1378 object_class,
1379 PROP_ANIMATE,
1380 g_param_spec_boolean (
1381 "animate",
1382 "Animate Images",
1383 NULL,
1384 FALSE,
1385 G_PARAM_READWRITE));
1386
1387 g_object_class_install_property (
1388 object_class,
1389 PROP_CARET_MODE,
1390 g_param_spec_boolean (
1391 "caret-mode",
1392 "Caret Mode",
1393 NULL,
1394 FALSE,
1395 G_PARAM_READWRITE));
1396
1397 /* Inherited from ESelectableInterface */
1398 g_object_class_override_property (
1399 object_class,
1400 PROP_COPY_TARGET_LIST,
1401 "copy-target-list");
1402
1403 g_object_class_install_property (
1404 object_class,
1405 PROP_DISABLE_PRINTING,
1406 g_param_spec_boolean (
1407 "disable-printing",
1408 "Disable Printing",
1409 NULL,
1410 FALSE,
1411 G_PARAM_READWRITE |
1412 G_PARAM_CONSTRUCT));
1413
1414 g_object_class_install_property (
1415 object_class,
1416 PROP_DISABLE_SAVE_TO_DISK,
1417 g_param_spec_boolean (
1418 "disable-save-to-disk",
1419 "Disable Save-to-Disk",
1420 NULL,
1421 FALSE,
1422 G_PARAM_READWRITE |
1423 G_PARAM_CONSTRUCT));
1424
1425 g_object_class_install_property (
1426 object_class,
1427 PROP_EDITABLE,
1428 g_param_spec_boolean (
1429 "editable",
1430 "Editable",
1431 NULL,
1432 FALSE,
1433 G_PARAM_READWRITE));
1434
1435 g_object_class_install_property (
1436 object_class,
1437 PROP_INLINE_SPELLING,
1438 g_param_spec_boolean (
1439 "inline-spelling",
1440 "Inline Spelling",
1441 NULL,
1442 FALSE,
1443 G_PARAM_READWRITE));
1444
1445 g_object_class_install_property (
1446 object_class,
1447 PROP_MAGIC_LINKS,
1448 g_param_spec_boolean (
1449 "magic-links",
1450 "Magic Links",
1451 NULL,
1452 FALSE,
1453 G_PARAM_READWRITE));
1454
1455 g_object_class_install_property (
1456 object_class,
1457 PROP_MAGIC_SMILEYS,
1458 g_param_spec_boolean (
1459 "magic-smileys",
1460 "Magic Smileys",
1461 NULL,
1462 FALSE,
1463 G_PARAM_READWRITE));
1464
1465 g_object_class_install_property (
1466 object_class,
1467 PROP_OPEN_PROXY,
1468 g_param_spec_object (
1469 "open-proxy",
1470 "Open Proxy",
1471 NULL,
1472 GTK_TYPE_ACTION,
1473 G_PARAM_READWRITE));
1474
1475 /* Inherited from ESelectableInterface */
1476 g_object_class_override_property (
1477 object_class,
1478 PROP_PASTE_TARGET_LIST,
1479 "paste-target-list");
1480
1481 g_object_class_install_property (
1482 object_class,
1483 PROP_PRINT_PROXY,
1484 g_param_spec_object (
1485 "print-proxy",
1486 "Print Proxy",
1487 NULL,
1488 GTK_TYPE_ACTION,
1489 G_PARAM_READWRITE));
1490
1491 g_object_class_install_property (
1492 object_class,
1493 PROP_SAVE_AS_PROXY,
1494 g_param_spec_object (
1495 "save-as-proxy",
1496 "Save As Proxy",
1497 NULL,
1498 GTK_TYPE_ACTION,
1499 G_PARAM_READWRITE));
1500
1501 g_object_class_install_property (
1502 object_class,
1503 PROP_SELECTED_URI,
1504 g_param_spec_string (
1505 "selected-uri",
1506 "Selected URI",
1507 NULL,
1508 NULL,
1509 G_PARAM_READWRITE));
1510
1511 g_object_class_install_property (
1512 object_class,
1513 PROP_CURSOR_IMAGE,
1514 g_param_spec_object (
1515 "cursor-image",
1516 "Image animation at the mouse cursor",
1517 NULL,
1518 GDK_TYPE_PIXBUF_ANIMATION,
1519 G_PARAM_READWRITE));
1520
1521 signals[COPY_CLIPBOARD] = g_signal_new (
1522 "copy-clipboard",
1523 G_TYPE_FROM_CLASS (class),
1524 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1525 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, copy_clipboard),
1526 NULL, NULL,
1527 g_cclosure_marshal_VOID__VOID,
1528 G_TYPE_NONE, 0);
1529
1530 signals[CUT_CLIPBOARD] = g_signal_new (
1531 "cut-clipboard",
1532 G_TYPE_FROM_CLASS (class),
1533 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1534 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, cut_clipboard),
1535 NULL, NULL,
1536 g_cclosure_marshal_VOID__VOID,
1537 G_TYPE_NONE, 0);
1538
1539 signals[PASTE_CLIPBOARD] = g_signal_new (
1540 "paste-clipboard",
1541 G_TYPE_FROM_CLASS (class),
1542 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1543 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, paste_clipboard),
1544 NULL, NULL,
1545 g_cclosure_marshal_VOID__VOID,
1546 G_TYPE_NONE, 0);
1547
1548 signals[POPUP_EVENT] = g_signal_new (
1549 "popup-event",
1550 G_TYPE_FROM_CLASS (class),
1551 G_SIGNAL_RUN_LAST,
1552 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, popup_event),
1553 g_signal_accumulator_true_handled, NULL,
1554 e_marshal_BOOLEAN__BOXED_STRING,
1555 G_TYPE_BOOLEAN, 2,
1556 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1557 G_TYPE_STRING);
1558
1559 signals[STATUS_MESSAGE] = g_signal_new (
1560 "status-message",
1561 G_TYPE_FROM_CLASS (class),
1562 G_SIGNAL_RUN_LAST,
1563 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, status_message),
1564 NULL, NULL,
1565 g_cclosure_marshal_VOID__STRING,
1566 G_TYPE_NONE, 1,
1567 G_TYPE_STRING);
1568
1569 signals[STOP_LOADING] = g_signal_new (
1570 "stop-loading",
1571 G_TYPE_FROM_CLASS (class),
1572 G_SIGNAL_RUN_LAST,
1573 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, stop_loading),
1574 NULL, NULL,
1575 g_cclosure_marshal_VOID__VOID,
1576 G_TYPE_NONE, 0);
1577
1578 signals[UPDATE_ACTIONS] = g_signal_new (
1579 "update-actions",
1580 G_TYPE_FROM_CLASS (class),
1581 G_SIGNAL_RUN_LAST,
1582 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, update_actions),
1583 NULL, NULL,
1584 g_cclosure_marshal_VOID__VOID,
1585 G_TYPE_NONE, 0);
1586
1587 /* return TRUE when a signal handler processed the mailto URI */
1588 signals[PROCESS_MAILTO] = g_signal_new (
1589 "process-mailto",
1590 G_TYPE_FROM_CLASS (class),
1591 G_SIGNAL_RUN_LAST,
1592 G_STRUCT_OFFSET (EWebViewGtkHTMLClass, process_mailto),
1593 NULL, NULL,
1594 e_marshal_BOOLEAN__STRING,
1595 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
1596 }
1597
1598 static void
1599 e_web_view_gtkhtml_alert_sink_init (EAlertSinkInterface *interface)
1600 {
1601 interface->submit_alert = web_view_gtkhtml_submit_alert;
1602 }
1603
1604 static void
1605 e_web_view_gtkhtml_selectable_init (ESelectableInterface *interface)
1606 {
1607 interface->update_actions = web_view_gtkhtml_selectable_update_actions;
1608 interface->cut_clipboard = web_view_gtkhtml_selectable_cut_clipboard;
1609 interface->copy_clipboard = web_view_gtkhtml_selectable_copy_clipboard;
1610 interface->paste_clipboard = web_view_gtkhtml_selectable_paste_clipboard;
1611 interface->select_all = web_view_gtkhtml_selectable_select_all;
1612 }
1613
1614 static void
1615 e_web_view_gtkhtml_init (EWebViewGtkHTML *web_view)
1616 {
1617 GtkUIManager *ui_manager;
1618 GtkActionGroup *action_group;
1619 GtkTargetList *target_list;
1620 EPopupAction *popup_action;
1621 const gchar *domain = GETTEXT_PACKAGE;
1622 const gchar *id;
1623 GError *error = NULL;
1624
1625 web_view->priv = E_WEB_VIEW_GTKHTML_GET_PRIVATE (web_view);
1626
1627 ui_manager = gtk_ui_manager_new ();
1628 web_view->priv->ui_manager = ui_manager;
1629
1630 g_signal_connect_swapped (
1631 ui_manager, "connect-proxy",
1632 G_CALLBACK (web_view_gtkhtml_connect_proxy_cb), web_view);
1633
1634 target_list = gtk_target_list_new (NULL, 0);
1635 web_view->priv->copy_target_list = target_list;
1636
1637 target_list = gtk_target_list_new (NULL, 0);
1638 web_view->priv->paste_target_list = target_list;
1639
1640 action_group = gtk_action_group_new ("uri");
1641 gtk_action_group_set_translation_domain (action_group, domain);
1642 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1643 g_object_unref (action_group);
1644
1645 gtk_action_group_add_actions (
1646 action_group, uri_entries,
1647 G_N_ELEMENTS (uri_entries), web_view);
1648
1649 action_group = gtk_action_group_new ("http");
1650 gtk_action_group_set_translation_domain (action_group, domain);
1651 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1652 g_object_unref (action_group);
1653
1654 gtk_action_group_add_actions (
1655 action_group, http_entries,
1656 G_N_ELEMENTS (http_entries), web_view);
1657
1658 action_group = gtk_action_group_new ("mailto");
1659 gtk_action_group_set_translation_domain (action_group, domain);
1660 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1661 g_object_unref (action_group);
1662
1663 gtk_action_group_add_actions (
1664 action_group, mailto_entries,
1665 G_N_ELEMENTS (mailto_entries), web_view);
1666
1667 action_group = gtk_action_group_new ("image");
1668 gtk_action_group_set_translation_domain (action_group, domain);
1669 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1670 g_object_unref (action_group);
1671
1672 gtk_action_group_add_actions (
1673 action_group, image_entries,
1674 G_N_ELEMENTS (image_entries), web_view);
1675
1676 action_group = gtk_action_group_new ("selection");
1677 gtk_action_group_set_translation_domain (action_group, domain);
1678 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1679 g_object_unref (action_group);
1680
1681 gtk_action_group_add_actions (
1682 action_group, selection_entries,
1683 G_N_ELEMENTS (selection_entries), web_view);
1684
1685 action_group = gtk_action_group_new ("standard");
1686 gtk_action_group_set_translation_domain (action_group, domain);
1687 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1688 g_object_unref (action_group);
1689
1690 gtk_action_group_add_actions (
1691 action_group, standard_entries,
1692 G_N_ELEMENTS (standard_entries), web_view);
1693
1694 popup_action = e_popup_action_new ("open");
1695 gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
1696 g_object_unref (popup_action);
1697
1698 g_object_bind_property (
1699 web_view, "open-proxy",
1700 popup_action, "related-action",
1701 G_BINDING_BIDIRECTIONAL |
1702 G_BINDING_SYNC_CREATE);
1703
1704 /* Support lockdown. */
1705
1706 action_group = gtk_action_group_new ("lockdown-printing");
1707 gtk_action_group_set_translation_domain (action_group, domain);
1708 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1709 g_object_unref (action_group);
1710
1711 popup_action = e_popup_action_new ("print");
1712 gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
1713 g_object_unref (popup_action);
1714
1715 g_object_bind_property (
1716 web_view, "print-proxy",
1717 popup_action, "related-action",
1718 G_BINDING_BIDIRECTIONAL |
1719 G_BINDING_SYNC_CREATE);
1720
1721 action_group = gtk_action_group_new ("lockdown-save-to-disk");
1722 gtk_action_group_set_translation_domain (action_group, domain);
1723 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1724 g_object_unref (action_group);
1725
1726 popup_action = e_popup_action_new ("save-as");
1727 gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
1728 g_object_unref (popup_action);
1729
1730 g_object_bind_property (
1731 web_view, "save-as-proxy",
1732 popup_action, "related-action",
1733 G_BINDING_BIDIRECTIONAL |
1734 G_BINDING_SYNC_CREATE);
1735
1736 /* Because we are loading from a hard-coded string, there is
1737 * no chance of I/O errors. Failure here implies a malformed
1738 * UI definition. Full stop. */
1739 gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
1740 if (error != NULL)
1741 g_error ("%s", error->message);
1742
1743 id = "org.gnome.evolution.webview";
1744 e_plugin_ui_register_manager (ui_manager, id, web_view);
1745 e_plugin_ui_enable_manager (ui_manager, id);
1746
1747 e_extensible_load_extensions (E_EXTENSIBLE (web_view));
1748 }
1749
1750 GtkWidget *
1751 e_web_view_gtkhtml_new (void)
1752 {
1753 return g_object_new (E_TYPE_WEB_VIEW_GTKHTML, NULL);
1754 }
1755
1756 void
1757 e_web_view_gtkhtml_clear (EWebViewGtkHTML *web_view)
1758 {
1759 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1760
1761 gtk_html_load_empty (GTK_HTML (web_view));
1762 }
1763
1764 void
1765 e_web_view_gtkhtml_load_string (EWebViewGtkHTML *web_view,
1766 const gchar *string)
1767 {
1768 EWebViewGtkHTMLClass *class;
1769
1770 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1771
1772 class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
1773 g_return_if_fail (class->load_string != NULL);
1774
1775 class->load_string (web_view, string);
1776 }
1777
1778 gboolean
1779 e_web_view_gtkhtml_get_animate (EWebViewGtkHTML *web_view)
1780 {
1781 /* XXX This is just here to maintain symmetry
1782 * with e_web_view_set_animate(). */
1783
1784 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1785
1786 return gtk_html_get_animate (GTK_HTML (web_view));
1787 }
1788
1789 void
1790 e_web_view_gtkhtml_set_animate (EWebViewGtkHTML *web_view,
1791 gboolean animate)
1792 {
1793 /* XXX GtkHTML does not utilize GObject properties as well
1794 * as it could. This just wraps gtk_html_set_animate()
1795 * so we can get a "notify::animate" signal. */
1796
1797 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1798
1799 gtk_html_set_animate (GTK_HTML (web_view), animate);
1800
1801 g_object_notify (G_OBJECT (web_view), "animate");
1802 }
1803
1804 gboolean
1805 e_web_view_gtkhtml_get_caret_mode (EWebViewGtkHTML *web_view)
1806 {
1807 /* XXX This is just here to maintain symmetry
1808 * with e_web_view_set_caret_mode(). */
1809
1810 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1811
1812 return gtk_html_get_caret_mode (GTK_HTML (web_view));
1813 }
1814
1815 void
1816 e_web_view_gtkhtml_set_caret_mode (EWebViewGtkHTML *web_view,
1817 gboolean caret_mode)
1818 {
1819 /* XXX GtkHTML does not utilize GObject properties as well
1820 * as it could. This just wraps gtk_html_set_caret_mode()
1821 * so we can get a "notify::caret-mode" signal. */
1822
1823 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1824
1825 gtk_html_set_caret_mode (GTK_HTML (web_view), caret_mode);
1826
1827 g_object_notify (G_OBJECT (web_view), "caret-mode");
1828 }
1829
1830 GtkTargetList *
1831 e_web_view_gtkhtml_get_copy_target_list (EWebViewGtkHTML *web_view)
1832 {
1833 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
1834
1835 return web_view->priv->copy_target_list;
1836 }
1837
1838 gboolean
1839 e_web_view_gtkhtml_get_disable_printing (EWebViewGtkHTML *web_view)
1840 {
1841 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1842
1843 return web_view->priv->disable_printing;
1844 }
1845
1846 void
1847 e_web_view_gtkhtml_set_disable_printing (EWebViewGtkHTML *web_view,
1848 gboolean disable_printing)
1849 {
1850 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1851
1852 web_view->priv->disable_printing = disable_printing;
1853
1854 g_object_notify (G_OBJECT (web_view), "disable-printing");
1855 }
1856
1857 gboolean
1858 e_web_view_gtkhtml_get_disable_save_to_disk (EWebViewGtkHTML *web_view)
1859 {
1860 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1861
1862 return web_view->priv->disable_save_to_disk;
1863 }
1864
1865 void
1866 e_web_view_gtkhtml_set_disable_save_to_disk (EWebViewGtkHTML *web_view,
1867 gboolean disable_save_to_disk)
1868 {
1869 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1870
1871 web_view->priv->disable_save_to_disk = disable_save_to_disk;
1872
1873 g_object_notify (G_OBJECT (web_view), "disable-save-to-disk");
1874 }
1875
1876 gboolean
1877 e_web_view_gtkhtml_get_editable (EWebViewGtkHTML *web_view)
1878 {
1879 /* XXX This is just here to maintain symmetry
1880 * with e_web_view_set_editable(). */
1881
1882 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1883
1884 return gtk_html_get_editable (GTK_HTML (web_view));
1885 }
1886
1887 void
1888 e_web_view_gtkhtml_set_editable (EWebViewGtkHTML *web_view,
1889 gboolean editable)
1890 {
1891 /* XXX GtkHTML does not utilize GObject properties as well
1892 * as it could. This just wraps gtk_html_set_editable()
1893 * so we can get a "notify::editable" signal. */
1894
1895 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1896
1897 gtk_html_set_editable (GTK_HTML (web_view), editable);
1898
1899 g_object_notify (G_OBJECT (web_view), "editable");
1900 }
1901
1902 gboolean
1903 e_web_view_gtkhtml_get_inline_spelling (EWebViewGtkHTML *web_view)
1904 {
1905 /* XXX This is just here to maintain symmetry
1906 * with e_web_view_set_inline_spelling(). */
1907
1908 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1909
1910 return gtk_html_get_inline_spelling (GTK_HTML (web_view));
1911 }
1912
1913 void
1914 e_web_view_gtkhtml_set_inline_spelling (EWebViewGtkHTML *web_view,
1915 gboolean inline_spelling)
1916 {
1917 /* XXX GtkHTML does not utilize GObject properties as well
1918 * as it could. This just wraps gtk_html_set_inline_spelling()
1919 * so we get a "notify::inline-spelling" signal. */
1920
1921 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1922
1923 gtk_html_set_inline_spelling (GTK_HTML (web_view), inline_spelling);
1924
1925 g_object_notify (G_OBJECT (web_view), "inline-spelling");
1926 }
1927
1928 gboolean
1929 e_web_view_gtkhtml_get_magic_links (EWebViewGtkHTML *web_view)
1930 {
1931 /* XXX This is just here to maintain symmetry
1932 * with e_web_view_set_magic_links(). */
1933
1934 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1935
1936 return gtk_html_get_magic_links (GTK_HTML (web_view));
1937 }
1938
1939 void
1940 e_web_view_gtkhtml_set_magic_links (EWebViewGtkHTML *web_view,
1941 gboolean magic_links)
1942 {
1943 /* XXX GtkHTML does not utilize GObject properties as well
1944 * as it could. This just wraps gtk_html_set_magic_links()
1945 * so we can get a "notify::magic-links" signal. */
1946
1947 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1948
1949 gtk_html_set_magic_links (GTK_HTML (web_view), magic_links);
1950
1951 g_object_notify (G_OBJECT (web_view), "magic-links");
1952 }
1953
1954 gboolean
1955 e_web_view_gtkhtml_get_magic_smileys (EWebViewGtkHTML *web_view)
1956 {
1957 /* XXX This is just here to maintain symmetry
1958 * with e_web_view_set_magic_smileys(). */
1959
1960 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
1961
1962 return gtk_html_get_magic_smileys (GTK_HTML (web_view));
1963 }
1964
1965 void
1966 e_web_view_gtkhtml_set_magic_smileys (EWebViewGtkHTML *web_view,
1967 gboolean magic_smileys)
1968 {
1969 /* XXX GtkHTML does not utilize GObject properties as well
1970 * as it could. This just wraps gtk_html_set_magic_smileys()
1971 * so we can get a "notify::magic-smileys" signal. */
1972
1973 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1974
1975 gtk_html_set_magic_smileys (GTK_HTML (web_view), magic_smileys);
1976
1977 g_object_notify (G_OBJECT (web_view), "magic-smileys");
1978 }
1979
1980 const gchar *
1981 e_web_view_gtkhtml_get_selected_uri (EWebViewGtkHTML *web_view)
1982 {
1983 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
1984
1985 return web_view->priv->selected_uri;
1986 }
1987
1988 void
1989 e_web_view_gtkhtml_set_selected_uri (EWebViewGtkHTML *web_view,
1990 const gchar *selected_uri)
1991 {
1992 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
1993
1994 g_free (web_view->priv->selected_uri);
1995 web_view->priv->selected_uri = g_strdup (selected_uri);
1996
1997 g_object_notify (G_OBJECT (web_view), "selected-uri");
1998 }
1999
2000 GdkPixbufAnimation *
2001 e_web_view_gtkhtml_get_cursor_image (EWebViewGtkHTML *web_view)
2002 {
2003 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2004
2005 return web_view->priv->cursor_image;
2006 }
2007
2008 void
2009 e_web_view_gtkhtml_set_cursor_image (EWebViewGtkHTML *web_view,
2010 GdkPixbufAnimation *image)
2011 {
2012 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2013
2014 if (image != NULL)
2015 g_object_ref (image);
2016
2017 if (web_view->priv->cursor_image != NULL)
2018 g_object_unref (web_view->priv->cursor_image);
2019
2020 web_view->priv->cursor_image = image;
2021
2022 g_object_notify (G_OBJECT (web_view), "cursor-image");
2023 }
2024
2025 GtkAction *
2026 e_web_view_gtkhtml_get_open_proxy (EWebViewGtkHTML *web_view)
2027 {
2028 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
2029
2030 return web_view->priv->open_proxy;
2031 }
2032
2033 void
2034 e_web_view_gtkhtml_set_open_proxy (EWebViewGtkHTML *web_view,
2035 GtkAction *open_proxy)
2036 {
2037 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2038
2039 if (open_proxy != NULL) {
2040 g_return_if_fail (GTK_IS_ACTION (open_proxy));
2041 g_object_ref (open_proxy);
2042 }
2043
2044 if (web_view->priv->open_proxy != NULL)
2045 g_object_unref (web_view->priv->open_proxy);
2046
2047 web_view->priv->open_proxy = open_proxy;
2048
2049 g_object_notify (G_OBJECT (web_view), "open-proxy");
2050 }
2051
2052 GtkTargetList *
2053 e_web_view_gtkhtml_get_paste_target_list (EWebViewGtkHTML *web_view)
2054 {
2055 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2056
2057 return web_view->priv->paste_target_list;
2058 }
2059
2060 GtkAction *
2061 e_web_view_gtkhtml_get_print_proxy (EWebViewGtkHTML *web_view)
2062 {
2063 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
2064
2065 return web_view->priv->print_proxy;
2066 }
2067
2068 void
2069 e_web_view_gtkhtml_set_print_proxy (EWebViewGtkHTML *web_view,
2070 GtkAction *print_proxy)
2071 {
2072 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2073
2074 if (print_proxy != NULL) {
2075 g_return_if_fail (GTK_IS_ACTION (print_proxy));
2076 g_object_ref (print_proxy);
2077 }
2078
2079 if (web_view->priv->print_proxy != NULL)
2080 g_object_unref (web_view->priv->print_proxy);
2081
2082 web_view->priv->print_proxy = print_proxy;
2083
2084 g_object_notify (G_OBJECT (web_view), "print-proxy");
2085 }
2086
2087 GtkAction *
2088 e_web_view_gtkhtml_get_save_as_proxy (EWebViewGtkHTML *web_view)
2089 {
2090 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
2091
2092 return web_view->priv->save_as_proxy;
2093 }
2094
2095 void
2096 e_web_view_gtkhtml_set_save_as_proxy (EWebViewGtkHTML *web_view,
2097 GtkAction *save_as_proxy)
2098 {
2099 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2100
2101 if (save_as_proxy != NULL) {
2102 g_return_if_fail (GTK_IS_ACTION (save_as_proxy));
2103 g_object_ref (save_as_proxy);
2104 }
2105
2106 if (web_view->priv->save_as_proxy != NULL)
2107 g_object_unref (web_view->priv->save_as_proxy);
2108
2109 web_view->priv->save_as_proxy = save_as_proxy;
2110
2111 g_object_notify (G_OBJECT (web_view), "save-as-proxy");
2112 }
2113
2114 GtkAction *
2115 e_web_view_gtkhtml_get_action (EWebViewGtkHTML *web_view,
2116 const gchar *action_name)
2117 {
2118 GtkUIManager *ui_manager;
2119
2120 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2121 g_return_val_if_fail (action_name != NULL, NULL);
2122
2123 ui_manager = e_web_view_gtkhtml_get_ui_manager (web_view);
2124
2125 return e_lookup_action (ui_manager, action_name);
2126 }
2127
2128 GtkActionGroup *
2129 e_web_view_gtkhtml_get_action_group (EWebViewGtkHTML *web_view,
2130 const gchar *group_name)
2131 {
2132 GtkUIManager *ui_manager;
2133
2134 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2135 g_return_val_if_fail (group_name != NULL, NULL);
2136
2137 ui_manager = e_web_view_gtkhtml_get_ui_manager (web_view);
2138
2139 return e_lookup_action_group (ui_manager, group_name);
2140 }
2141
2142 gchar *
2143 e_web_view_gtkhtml_extract_uri (EWebViewGtkHTML *web_view,
2144 GdkEventButton *event,
2145 GtkHTML *frame)
2146 {
2147 EWebViewGtkHTMLClass *class;
2148
2149 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2150
2151 if (frame == NULL)
2152 frame = GTK_HTML (web_view);
2153
2154 class = E_WEB_VIEW_GTKHTML_GET_CLASS (web_view);
2155 g_return_val_if_fail (class->extract_uri != NULL, NULL);
2156
2157 return class->extract_uri (web_view, event, frame);
2158 }
2159
2160 void
2161 e_web_view_gtkhtml_copy_clipboard (EWebViewGtkHTML *web_view)
2162 {
2163 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2164
2165 g_signal_emit (web_view, signals[COPY_CLIPBOARD], 0);
2166 }
2167
2168 void
2169 e_web_view_gtkhtml_cut_clipboard (EWebViewGtkHTML *web_view)
2170 {
2171 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2172
2173 g_signal_emit (web_view, signals[CUT_CLIPBOARD], 0);
2174 }
2175
2176 gboolean
2177 e_web_view_gtkhtml_is_selection_active (EWebViewGtkHTML *web_view)
2178 {
2179 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
2180
2181 return gtk_html_command (GTK_HTML (web_view), "is-selection-active");
2182 }
2183
2184 void
2185 e_web_view_gtkhtml_paste_clipboard (EWebViewGtkHTML *web_view)
2186 {
2187 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2188
2189 g_signal_emit (web_view, signals[PASTE_CLIPBOARD], 0);
2190 }
2191
2192 gboolean
2193 e_web_view_gtkhtml_scroll_forward (EWebViewGtkHTML *web_view)
2194 {
2195 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
2196
2197 return gtk_html_command (GTK_HTML (web_view), "scroll-forward");
2198 }
2199
2200 gboolean
2201 e_web_view_gtkhtml_scroll_backward (EWebViewGtkHTML *web_view)
2202 {
2203 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), FALSE);
2204
2205 return gtk_html_command (GTK_HTML (web_view), "scroll-backward");
2206 }
2207
2208 void
2209 e_web_view_gtkhtml_select_all (EWebViewGtkHTML *web_view)
2210 {
2211 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2212
2213 gtk_html_command (GTK_HTML (web_view), "select-all");
2214 }
2215
2216 void
2217 e_web_view_gtkhtml_unselect_all (EWebViewGtkHTML *web_view)
2218 {
2219 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2220
2221 gtk_html_command (GTK_HTML (web_view), "unselect-all");
2222 }
2223
2224 void
2225 e_web_view_gtkhtml_zoom_100 (EWebViewGtkHTML *web_view)
2226 {
2227 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2228
2229 gtk_html_command (GTK_HTML (web_view), "zoom-reset");
2230 }
2231
2232 void
2233 e_web_view_gtkhtml_zoom_in (EWebViewGtkHTML *web_view)
2234 {
2235 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2236
2237 gtk_html_command (GTK_HTML (web_view), "zoom-in");
2238 }
2239
2240 void
2241 e_web_view_gtkhtml_zoom_out (EWebViewGtkHTML *web_view)
2242 {
2243 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2244
2245 gtk_html_command (GTK_HTML (web_view), "zoom-out");
2246 }
2247
2248 GtkUIManager *
2249 e_web_view_gtkhtml_get_ui_manager (EWebViewGtkHTML *web_view)
2250 {
2251 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2252
2253 return web_view->priv->ui_manager;
2254 }
2255
2256 GtkWidget *
2257 e_web_view_gtkhtml_get_popup_menu (EWebViewGtkHTML *web_view)
2258 {
2259 GtkUIManager *ui_manager;
2260 GtkWidget *menu;
2261
2262 g_return_val_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view), NULL);
2263
2264 ui_manager = e_web_view_gtkhtml_get_ui_manager (web_view);
2265 menu = gtk_ui_manager_get_widget (ui_manager, "/context");
2266 g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
2267
2268 return menu;
2269 }
2270
2271 void
2272 e_web_view_gtkhtml_show_popup_menu (EWebViewGtkHTML *web_view,
2273 GdkEventButton *event,
2274 GtkMenuPositionFunc func,
2275 gpointer user_data)
2276 {
2277 GtkWidget *menu;
2278
2279 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2280
2281 e_web_view_gtkhtml_update_actions (web_view);
2282
2283 menu = e_web_view_gtkhtml_get_popup_menu (web_view);
2284
2285 if (event != NULL)
2286 gtk_menu_popup (
2287 GTK_MENU (menu), NULL, NULL, func,
2288 user_data, event->button, event->time);
2289 else
2290 gtk_menu_popup (
2291 GTK_MENU (menu), NULL, NULL, func,
2292 user_data, 0, gtk_get_current_event_time ());
2293 }
2294
2295 void
2296 e_web_view_gtkhtml_status_message (EWebViewGtkHTML *web_view,
2297 const gchar *status_message)
2298 {
2299 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2300
2301 g_signal_emit (web_view, signals[STATUS_MESSAGE], 0, status_message);
2302 }
2303
2304 void
2305 e_web_view_gtkhtml_stop_loading (EWebViewGtkHTML *web_view)
2306 {
2307 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2308
2309 g_signal_emit (web_view, signals[STOP_LOADING], 0);
2310 }
2311
2312 void
2313 e_web_view_gtkhtml_update_actions (EWebViewGtkHTML *web_view)
2314 {
2315 g_return_if_fail (E_IS_WEB_VIEW_GTKHTML (web_view));
2316
2317 g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0);
2318 }