aboutsummaryrefslogtreecommitdiffstats
path: root/mail/e-mail-display.c
diff options
context:
space:
mode:
Diffstat (limited to 'mail/e-mail-display.c')
-rw-r--r--mail/e-mail-display.c1072
1 files changed, 1072 insertions, 0 deletions
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
new file mode 100644
index 0000000000..c29328b36b
--- /dev/null
+++ b/mail/e-mail-display.c
@@ -0,0 +1,1072 @@
+/*
+ * e-mail-display.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-display.h"
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+#include "e-util/e-plugin-ui.h"
+#include "mail/em-composer-utils.h"
+#include "mail/em-utils.h"
+
+#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
+
+struct _EMailDisplayPrivate {
+ EMFormatHTML *formatter;
+ GtkUIManager *ui_manager;
+ gchar *selected_uri;
+};
+
+enum {
+ PROP_0,
+ PROP_ANIMATE,
+ PROP_CARET_MODE,
+ PROP_FORMATTER,
+ PROP_SELECTED_URI
+};
+
+enum {
+ POPUP_EVENT,
+ STATUS_MESSAGE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static const gchar *ui =
+"<ui>"
+" <popup name='context'>"
+" <menuitem action='http-open'/>"
+" <menuitem action='send-message'/>"
+" <menuitem action='uri-copy'/>"
+" <menuitem action='add-to-address-book'/>"
+" <menuitem action='mailto-copy'/>"
+" <menu action='search-folder-menu'>"
+" <menuitem action='search-folder-sender'/>"
+" <menuitem action='search-folder-recipient'/>"
+" </menu>"
+" </popup>"
+"</ui>";
+
+static void
+action_add_to_address_book_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ CamelURL *curl;
+ const gchar *uri;
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (display));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ /* This should work because we checked it in update_actions(). */
+ curl = camel_url_new (uri, NULL);
+ g_return_if_fail (curl != NULL);
+
+ if (curl->path != NULL && *curl->path != '\0')
+ em_utils_add_address (parent, curl->path);
+
+ camel_url_free (curl);
+}
+
+static void
+action_http_open_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ const gchar *uri;
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (display));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ e_show_uri (parent, uri);
+}
+
+static void
+action_mailto_copy_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ CamelURL *curl;
+ CamelInternetAddress *inet_addr;
+ GtkClipboard *clipboard;
+ const gchar *uri;
+ gchar *text;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ /* This should work because we checked it in update_actions(). */
+ curl = camel_url_new (uri, NULL);
+ g_return_if_fail (curl != NULL);
+
+ inet_addr = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path);
+ text = camel_address_encode (CAMEL_ADDRESS (inet_addr));
+ if (text == NULL || *text == '\0')
+ text = g_strdup (uri + strlen ("mailto:"));
+
+ camel_object_unref (inet_addr);
+ camel_url_free (curl);
+
+ gtk_clipboard_set_text (clipboard, text, -1);
+ gtk_clipboard_store (clipboard);
+
+ g_free (text);
+}
+
+static void
+action_send_message_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ const gchar *uri;
+
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ em_utils_compose_new_message_with_mailto (uri, NULL);
+}
+
+static void
+action_uri_copy_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ GtkClipboard *clipboard;
+ const gchar *uri;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ gtk_clipboard_set_text (clipboard, uri, -1);
+ gtk_clipboard_store (clipboard);
+}
+
+static GtkActionEntry uri_entries[] = {
+
+ { "uri-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy Link Location"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_uri_copy_cb) },
+};
+
+static GtkActionEntry http_entries[] = {
+
+ { "http-open",
+ "emblem-web",
+ N_("_Open Link in Browser"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_http_open_cb) },
+};
+
+static GtkActionEntry mailto_entries[] = {
+
+ { "add-to-address-book",
+ "contact-new",
+ N_("_Add to Address Book..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_add_to_address_book_cb) },
+
+ { "mailto-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy Email Address"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mailto_copy_cb) },
+
+ { "search-folder-recipient",
+ NULL,
+ N_("_To This Address"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ NULL /* Handled by EMailReader */ },
+
+ { "search-folder-sender",
+ NULL,
+ N_("_From This Address"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ NULL /* Handled by EMailReader */ },
+
+ { "send-message",
+ "mail-message-new",
+ N_("_Send New Message To..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_send_message_cb) },
+
+ /*** Menus ***/
+
+ { "search-folder-menu",
+ "folder-saved-search",
+ N_("Create Search _Folder"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static gboolean
+mail_display_emit_popup_event (EMailDisplay *display,
+ GdkEventButton *event,
+ const gchar *uri,
+ EMFormatPURI *puri)
+{
+ CamelMimePart *mime_part;
+ gboolean stop_handlers = FALSE;
+
+ mime_part = (puri != NULL) ? puri->part : NULL;
+
+ g_signal_emit (
+ display, signals[POPUP_EVENT], 0,
+ event, uri, mime_part, &stop_handlers);
+
+ return stop_handlers;
+}
+
+static void
+mail_display_emit_status_message (EMailDisplay *display,
+ const gchar *status_message)
+{
+ g_signal_emit (display, signals[STATUS_MESSAGE], 0, status_message);
+}
+
+static void
+mail_display_get_uri_puri (EMailDisplay *display,
+ GdkEventButton *event,
+ GtkHTML *html,
+ gchar **uri,
+ EMFormatPURI **puri)
+{
+ EMFormat *formatter;
+ gchar *text_uri;
+ gchar *image_uri;
+ gboolean is_cid;
+
+ formatter = EM_FORMAT (display->priv->formatter);
+
+ if (event != NULL) {
+ text_uri = gtk_html_get_url_at (html, event->x, event->y);
+ image_uri = gtk_html_get_image_src_at (html, event->x, event->y);
+ } else {
+ text_uri = gtk_html_get_cursor_url (html);
+ image_uri = gtk_html_get_cursor_image_src (html);
+ }
+
+ is_cid = (image_uri != NULL) &&
+ (g_ascii_strncasecmp (image_uri, "cid:", 4) == 0);
+
+ if (image_uri != NULL) {
+ if (strstr (image_uri, "://") == NULL && !is_cid) {
+ gchar *temp;
+
+ temp = g_strconcat ("file://", image_uri, NULL);
+ g_free (image_uri);
+ image_uri = temp;
+ }
+ }
+
+ if (puri != NULL) {
+ if (text_uri != NULL)
+ *puri = em_format_find_puri (formatter, text_uri);
+
+ if (*puri == NULL && image_uri != NULL)
+ *puri = em_format_find_puri (formatter, image_uri);
+ }
+
+ if (uri != NULL) {
+ *uri = NULL;
+ if (is_cid) {
+ if (text_uri != NULL)
+ *uri = g_strdup_printf (
+ "%s\n%s", text_uri, image_uri);
+ else {
+ *uri = image_uri;
+ image_uri = NULL;
+ }
+ } else {
+ *uri = text_uri;
+ text_uri = NULL;
+ }
+ }
+
+ g_free (text_uri);
+ g_free (image_uri);
+}
+
+static gboolean
+mail_display_button_press_event_cb (EMailDisplay *display,
+ GdkEventButton *event,
+ GtkHTML *html)
+{
+ EMFormatPURI *puri = NULL;
+ gboolean finished = TRUE;
+ gchar *uri = NULL;
+
+ /* The GtkHTML object may be the EMailDisplay itself
+ * or an inner iframe. */
+
+ if (event->button != 3)
+ return FALSE;
+
+ mail_display_get_uri_puri (display, event, html, &uri, &puri);
+
+ if (uri == NULL || g_str_has_prefix (uri, "##")) {
+ g_free (uri);
+ return FALSE;
+ }
+
+ finished = mail_display_emit_popup_event (display, event, uri, puri);
+
+ g_free (uri);
+
+ return finished;
+}
+
+static void
+mail_display_update_formatter_colors (EMailDisplay *display)
+{
+ EMFormatHTMLColorType type;
+ EMFormatHTML *formatter;
+ GdkColor *color;
+ GtkStyle *style;
+ gint state;
+
+ state = GTK_WIDGET_STATE (display);
+ formatter = display->priv->formatter;
+
+ style = gtk_widget_get_style (GTK_WIDGET (display));
+ if (style == NULL)
+ return;
+
+ g_object_freeze_notify (G_OBJECT (formatter));
+
+ color = &style->bg[state];
+ type = EM_FORMAT_HTML_COLOR_BODY;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->base[GTK_STATE_NORMAL];
+ type = EM_FORMAT_HTML_COLOR_CONTENT;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->dark[state];
+ type = EM_FORMAT_HTML_COLOR_FRAME;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->fg[state];
+ type = EM_FORMAT_HTML_COLOR_HEADER;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->text[state];
+ type = EM_FORMAT_HTML_COLOR_TEXT;
+ em_format_html_set_color (formatter, type, color);
+
+ g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+mail_display_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE:
+ e_mail_display_set_animate (
+ E_MAIL_DISPLAY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_CARET_MODE:
+ e_mail_display_set_caret_mode (
+ E_MAIL_DISPLAY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_FORMATTER:
+ e_mail_display_set_formatter (
+ E_MAIL_DISPLAY (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SELECTED_URI:
+ e_mail_display_set_selected_uri (
+ E_MAIL_DISPLAY (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_display_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE:
+ g_value_set_boolean (
+ value, e_mail_display_get_animate (
+ E_MAIL_DISPLAY (object)));
+ return;
+
+ case PROP_CARET_MODE:
+ g_value_set_boolean (
+ value, e_mail_display_get_caret_mode (
+ E_MAIL_DISPLAY (object)));
+ return;
+
+ case PROP_FORMATTER:
+ g_value_set_object (
+ value, e_mail_display_get_formatter (
+ E_MAIL_DISPLAY (object)));
+ return;
+
+ case PROP_SELECTED_URI:
+ g_value_set_string (
+ value, e_mail_display_get_selected_uri (
+ E_MAIL_DISPLAY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_display_dispose (GObject *object)
+{
+ EMailDisplayPrivate *priv;
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (object);
+
+ if (priv->formatter) {
+ g_object_unref (priv->formatter);
+ priv->formatter = NULL;
+ }
+
+ if (priv->ui_manager) {
+ g_object_unref (priv->ui_manager);
+ priv->ui_manager = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_display_realize (GtkWidget *widget)
+{
+ /* Chain up to parent's realize() method. */
+ GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+ mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
+}
+
+static void
+mail_display_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ EMailDisplayPrivate *priv;
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (widget);
+
+ /* Chain up to parent's style_set() method. */
+ GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
+
+ mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
+ em_format_redraw (EM_FORMAT (priv->formatter));
+}
+
+static gboolean
+mail_display_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EMailDisplay *display = E_MAIL_DISPLAY (widget);
+ GtkHTML *html = GTK_HTML (widget);
+
+ if (mail_display_button_press_event_cb (display, event, html))
+ return TRUE;
+
+ /* Chain up to parent's button_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ button_press_event (widget, event);
+}
+
+static gboolean
+mail_display_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ if (event->state & GDK_CONTROL_MASK) {
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ gtk_html_zoom_in (GTK_HTML (widget));
+ return TRUE;
+ case GDK_SCROLL_DOWN:
+ gtk_html_zoom_out (GTK_HTML (widget));
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+mail_display_link_clicked (GtkHTML *html,
+ const gchar *uri)
+{
+ EMailDisplayPrivate *priv;
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (html);
+ g_return_if_fail (priv->formatter != NULL);
+
+ if (g_str_has_prefix (uri, "##")) {
+ guint32 flags;
+
+ flags = priv->formatter->header_wrap_flags;
+
+ if (strcmp (uri, "##TO##") == 0) {
+ if (!(flags & EM_FORMAT_HTML_HEADER_TO))
+ flags |= EM_FORMAT_HTML_HEADER_TO;
+ else
+ flags &= ~EM_FORMAT_HTML_HEADER_TO;
+ } else if (strcmp (uri, "##CC##") == 0) {
+ if (!(flags & EM_FORMAT_HTML_HEADER_CC))
+ flags |= EM_FORMAT_HTML_HEADER_CC;
+ else
+ flags |= EM_FORMAT_HTML_HEADER_CC;
+ } else if (strcmp (uri, "##BCC##") == 0) {
+ if (!(flags & EM_FORMAT_HTML_HEADER_BCC))
+ flags |= EM_FORMAT_HTML_HEADER_BCC;
+ else
+ flags |= EM_FORMAT_HTML_HEADER_BCC;
+ }
+
+ priv->formatter->header_wrap_flags = flags;
+ em_format_redraw (EM_FORMAT (priv->formatter));
+
+ } else if (*uri == '#')
+ gtk_html_jump_to_anchor (html, uri + 1);
+
+ else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
+ /* ignore */ ;
+
+ else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
+ /* ignore */ ;
+
+ else {
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (html));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ e_show_uri (parent, uri);
+ }
+}
+
+static void
+mail_display_on_url (GtkHTML *html,
+ const gchar *uri)
+{
+ EMailDisplay *display;
+ CamelInternetAddress *address;
+ CamelURL *curl;
+ const gchar *format = NULL;
+ gchar *message = NULL;
+ gchar *who;
+
+ display = E_MAIL_DISPLAY (html);
+
+ if (uri == NULL || *uri == '\0')
+ goto exit;
+
+ if (g_str_has_prefix (uri, "mailto:"))
+ format = _("Click to mail %s");
+ else if (g_str_has_prefix (uri, "callto:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "h323:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "sip:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "##"))
+ message = g_strdup (_("Click to hide/unhide addresses"));
+ else
+ message = g_strdup_printf (_("Click to open %s"), uri);
+
+ if (format == NULL)
+ goto exit;
+
+ curl = camel_url_new (uri, NULL);
+ address = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (address), curl->path);
+ who = camel_address_format (CAMEL_ADDRESS (address));
+ camel_object_unref (address);
+ camel_url_free (curl);
+
+ if (who == NULL)
+ who = g_strdup (strchr (uri, ':') + 1);
+
+ message = g_strdup_printf (format, who);
+
+ g_free (who);
+
+exit:
+ mail_display_emit_status_message (display, message);
+
+ g_free (message);
+}
+
+static void
+mail_display_iframe_created (GtkHTML *html,
+ GtkHTML *iframe)
+{
+ g_signal_connect_swapped (
+ iframe, "button-press-event",
+ G_CALLBACK (mail_display_button_press_event_cb), html);
+}
+
+static gboolean
+mail_display_popup_event (EMailDisplay *display,
+ GdkEventButton *event,
+ const gchar *uri,
+ EMFormatPURI *puri)
+{
+ e_mail_display_set_selected_uri (display, uri);
+ e_mail_display_show_popup_menu (display, event, NULL, NULL);
+
+ return TRUE;
+}
+
+static void
+mail_display_class_init (EMailDisplayClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkHTMLClass *html_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_display_set_property;
+ object_class->get_property = mail_display_get_property;
+ object_class->dispose = mail_display_dispose;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->realize = mail_display_realize;
+ widget_class->style_set = mail_display_style_set;
+ widget_class->button_press_event = mail_display_button_press_event;
+ widget_class->scroll_event = mail_display_scroll_event;
+
+ html_class = GTK_HTML_CLASS (class);
+ html_class->link_clicked = mail_display_link_clicked;
+ html_class->on_url = mail_display_on_url;
+ html_class->iframe_created = mail_display_iframe_created;
+
+ class->popup_event = mail_display_popup_event;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ANIMATE,
+ g_param_spec_boolean (
+ "animate",
+ "Animate Images",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CARET_MODE,
+ g_param_spec_boolean (
+ "caret-mode",
+ "Caret Mode",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FORMATTER,
+ g_param_spec_object (
+ "formatter",
+ "HTML Formatter",
+ NULL,
+ EM_TYPE_FORMAT_HTML,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTED_URI,
+ g_param_spec_string (
+ "selected-uri",
+ "Selected URI",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ signals[POPUP_EVENT] = g_signal_new (
+ "popup-event",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailDisplayClass, popup_event),
+ g_signal_accumulator_true_handled, NULL,
+ e_marshal_BOOLEAN__BOXED_POINTER_POINTER,
+ G_TYPE_BOOLEAN, 3,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMailDisplayClass, status_message),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static void
+mail_display_init (EMailDisplay *display)
+{
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ const gchar *id;
+ GError *error = NULL;
+
+ display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
+
+ ui_manager = gtk_ui_manager_new ();
+ display->priv->ui_manager = ui_manager;
+
+ action_group = e_mail_display_add_action_group (display, "uri");
+
+ gtk_action_group_add_actions (
+ action_group, uri_entries,
+ G_N_ELEMENTS (uri_entries), display);
+
+ action_group = e_mail_display_add_action_group (display, "http");
+
+ gtk_action_group_add_actions (
+ action_group, http_entries,
+ G_N_ELEMENTS (http_entries), display);
+
+ action_group = e_mail_display_add_action_group (display, "mailto");
+
+ gtk_action_group_add_actions (
+ action_group, mailto_entries,
+ G_N_ELEMENTS (mailto_entries), display);
+
+ /* Because we are loading from a hard-coded string, there is
+ * no chance of I/O errors. Failure here implies a malformed
+ * UI definition. Full stop. */
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+ if (error != NULL)
+ g_error ("%s", error->message);
+
+ id = "org.gnome.evolution.mail.display";
+ e_plugin_ui_register_manager (ui_manager, id, display);
+ e_plugin_ui_enable_manager (ui_manager, id);
+}
+
+GType
+e_mail_display_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailDisplayClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_display_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailDisplay),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_display_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_HTML, "EMailDisplay", &type_info, 0);
+ }
+
+ return type;
+}
+
+gboolean
+e_mail_display_get_animate (EMailDisplay *display)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_mail_display_set_animate(). */
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ return gtk_html_get_animate (GTK_HTML (display));
+}
+
+void
+e_mail_display_set_animate (EMailDisplay *display,
+ gboolean animate)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_animate()
+ * so we can get a "notify::animate" signal. */
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ gtk_html_set_animate (GTK_HTML (display), animate);
+
+ g_object_notify (G_OBJECT (display), "animate");
+}
+
+gboolean
+e_mail_display_get_caret_mode (EMailDisplay *display)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_mail_display_set_caret_mode(). */
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ return gtk_html_get_caret_mode (GTK_HTML (display));
+}
+
+void
+e_mail_display_set_caret_mode (EMailDisplay *display,
+ gboolean caret_mode)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_caret_mode()
+ * so we can get a "notify::caret-mode" signal. */
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ gtk_html_set_caret_mode (GTK_HTML (display), caret_mode);
+
+ g_object_notify (G_OBJECT (display), "caret-mode");
+}
+
+EMFormatHTML *
+e_mail_display_get_formatter (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ return display->priv->formatter;
+}
+
+void
+e_mail_display_set_formatter (EMailDisplay *display,
+ EMFormatHTML *formatter)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+ g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
+
+ if (display->priv->formatter != NULL)
+ g_object_unref (display->priv->formatter);
+
+ display->priv->formatter = g_object_ref (formatter);
+
+ g_object_notify (G_OBJECT (display), "formatter");
+}
+
+const gchar *
+e_mail_display_get_selected_uri (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ return display->priv->selected_uri;
+}
+
+void
+e_mail_display_set_selected_uri (EMailDisplay *display,
+ const gchar *selected_uri)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ g_free (display->priv->selected_uri);
+ display->priv->selected_uri = g_strdup (selected_uri);
+
+ g_object_notify (G_OBJECT (display), "selected-uri");
+}
+
+GtkAction *
+e_mail_display_get_action (EMailDisplay *display,
+ const gchar *action_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ ui_manager = e_mail_display_get_ui_manager (display);
+
+ return e_lookup_action (ui_manager, action_name);
+}
+
+GtkActionGroup *
+e_mail_display_add_action_group (EMailDisplay *display,
+ const gchar *group_name)
+{
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ const gchar *domain;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+ g_return_val_if_fail (group_name != NULL, NULL);
+
+ ui_manager = e_mail_display_get_ui_manager (display);
+ domain = GETTEXT_PACKAGE;
+
+ action_group = gtk_action_group_new (group_name);
+ gtk_action_group_set_translation_domain (action_group, domain);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ g_object_unref (action_group);
+
+ return action_group;
+}
+
+GtkActionGroup *
+e_mail_display_get_action_group (EMailDisplay *display,
+ const gchar *group_name)
+{
+ GtkUIManager *ui_manager;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+ g_return_val_if_fail (group_name != NULL, NULL);
+
+ ui_manager = e_mail_display_get_ui_manager (display);
+
+ return e_lookup_action_group (ui_manager, group_name);
+}
+
+GtkWidget *
+e_mail_display_get_popup_menu (EMailDisplay *display)
+{
+ GtkUIManager *ui_manager;
+ GtkWidget *menu;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ ui_manager = e_mail_display_get_ui_manager (display);
+ menu = gtk_ui_manager_get_widget (ui_manager, "/context");
+ g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
+
+ return menu;
+}
+
+GtkUIManager *
+e_mail_display_get_ui_manager (EMailDisplay *display)
+{
+ EMailDisplayPrivate *priv;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
+
+ return priv->ui_manager;
+}
+
+void
+e_mail_display_show_popup_menu (EMailDisplay *display,
+ GdkEventButton *event,
+ GtkMenuPositionFunc func,
+ gpointer user_data)
+{
+ GtkWidget *menu;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ e_mail_display_update_actions (display);
+
+ menu = e_mail_display_get_popup_menu (display);
+
+ if (event != NULL)
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, func,
+ user_data, event->button, event->time);
+ else
+ gtk_menu_popup (
+ GTK_MENU (menu), NULL, NULL, func,
+ user_data, 0, gtk_get_current_event_time ());
+}
+
+void
+e_mail_display_update_actions (EMailDisplay *display)
+{
+ CamelURL *curl;
+ GtkActionGroup *action_group;
+ gboolean scheme_is_http;
+ gboolean scheme_is_mailto;
+ gboolean uri_is_valid;
+ gboolean visible;
+ const gchar *uri;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ uri = e_mail_display_get_selected_uri (display);
+ g_return_if_fail (uri != NULL);
+
+ /* Parse the URI early so we know if the actions will work. */
+ curl = camel_url_new (uri, NULL);
+ uri_is_valid = (curl != NULL);
+ camel_url_free (curl);
+
+ scheme_is_http =
+ (g_ascii_strncasecmp (uri, "http:", 5) == 0) ||
+ (g_ascii_strncasecmp (uri, "https:", 6) == 0);
+
+ scheme_is_mailto =
+ (g_ascii_strncasecmp (uri, "mailto:", 7) == 0);
+
+ /* Allow copying the URI even if it's malformed. */
+ visible = !scheme_is_mailto;
+ action_group = e_mail_display_get_action_group (display, "uri");
+ gtk_action_group_set_visible (action_group, visible);
+
+ visible = uri_is_valid && scheme_is_http;
+ action_group = e_mail_display_get_action_group (display, "http");
+ gtk_action_group_set_visible (action_group, visible);
+
+ visible = uri_is_valid && scheme_is_mailto;
+ action_group = e_mail_display_get_action_group (display, "mailto");
+ gtk_action_group_set_visible (action_group, visible);
+}