/* * 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 * * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #include "e-mail-display.h" #include #include #include #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 = "" " " " " " " " " " " " " " " " " " " " " " " ""; 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); }