From 6db0e254190a80cf1cccb3629442b78e76c55b36 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sat, 7 Nov 2009 22:09:32 -0500 Subject: Prototype an inline image plugin. Uses GtkImageView to display the image. --- configure.ac | 22 +++ mail/em-format-html-display.c | 2 + mail/em-format-html.c | 4 + plugins/image-inline/Makefile.am | 29 +++ plugins/image-inline/image-inline.c | 219 +++++++++++++++++++++ .../image-inline/org-gnome-image-inline.eplug.xml | 125 ++++++++++++ 6 files changed, 401 insertions(+) create mode 100644 plugins/image-inline/Makefile.am create mode 100644 plugins/image-inline/image-inline.c create mode 100644 plugins/image-inline/org-gnome-image-inline.eplug.xml diff --git a/configure.ac b/configure.ac index 731928106c..7115f98983 100644 --- a/configure.ac +++ b/configure.ac @@ -62,6 +62,7 @@ m4_define([hal_minimum_version], [0.5.4]) m4_define([libnotify_minimum_version], [0.3.0]) m4_define([gnome_pilot_minimum_version], [2.0.15]) m4_define([gweather_minimum_version], [2.25.3]) +m4_define([gtkimageview_minimum_version], [1.6]) dnl ****************************** dnl Compiler Warning Flags @@ -1542,6 +1543,26 @@ if test "x$enable_weather" = "xyes"; then fi fi +dnl ***************************************** +dnl image-inline plugin requires gtkimageview +dnl ***************************************** +AC_ARG_ENABLE([image-inline], + [AS_HELP_STRING([--enable-image-inline], + [Enable image-inline plugin @<:@default=yes@:>@])], + [enable_image_inline="$enableval"], [enable_image_inline=yes]) + +if test "x$enable_image_inline" = "xyes"; then + PKG_CHECK_MODULES(GTKIMAGEVIEW, gtkimageview >= gtkimageview_minimum_version, have_imageview=yes, have_imageview=no) + AC_SUBST(GTKIMAGEVIEW_CFLAGS) + AC_SUBST(GTKIMAGEVIEW_LIBS) + + if test "x$have_imageview" = "xyes"; then + plugins_standard="$plugins_standard image-inline" + else + AC_MSG_ERROR([gtkimageview is required for the image-inline plugin. Use --disable-image-inline to exclude the plugin.]) + fi +fi + dnl ********************************* dnl pst-import plugin requires libpst dnl ********************************* @@ -1762,6 +1783,7 @@ plugins/face/Makefile plugins/google-account-setup/Makefile plugins/groupwise-features/Makefile plugins/hula-account-setup/Makefile +plugins/image-inline/Makefile plugins/imap-features/Makefile plugins/itip-formatter/Makefile plugins/mail-notification/Makefile diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index 6a2f56525c..de64e2b15c 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -699,6 +699,7 @@ efhd_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormat /* ********************************************************************** */ static EMFormatHandler type_builtin_table[] = { +#if 0 { (gchar *) "image/gif", (EMFormatFunc)efhd_image }, { (gchar *) "image/jpeg", (EMFormatFunc)efhd_image }, { (gchar *) "image/png", (EMFormatFunc)efhd_image }, @@ -721,6 +722,7 @@ static EMFormatHandler type_builtin_table[] = { { (gchar *) "image/jpg", (EMFormatFunc)efhd_image }, { (gchar *) "image/pjpeg", (EMFormatFunc)efhd_image }, +#endif { (gchar *) "x-evolution/message/prefix", (EMFormatFunc)efhd_message_prefix }, { (gchar *) "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar } diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 47213dc5d5..29bb47653f 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -2105,6 +2105,7 @@ efh_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatH } static EMFormatHandler type_builtin_table[] = { +#if 0 { (gchar *) "image/gif", (EMFormatFunc)efh_image }, { (gchar *) "image/jpeg", (EMFormatFunc)efh_image }, { (gchar *) "image/png", (EMFormatFunc)efh_image }, @@ -2120,6 +2121,7 @@ static EMFormatHandler type_builtin_table[] = { { (gchar *) "image/x-portable-graymap", (EMFormatFunc)efh_image }, { (gchar *) "image/x-portable-pixmap", (EMFormatFunc)efh_image }, { (gchar *) "image/x-xpixmap", (EMFormatFunc)efh_image }, +#endif { (gchar *) "text/enriched", (EMFormatFunc)efh_text_enriched }, { (gchar *) "text/plain", (EMFormatFunc)efh_text_plain }, { (gchar *) "text/html", (EMFormatFunc)efh_text_html }, @@ -2133,8 +2135,10 @@ static EMFormatHandler type_builtin_table[] = { that some idiot mailer writers out there decide to pull out of their proverbials at random. */ +#if 0 { (gchar *) "image/jpg", (EMFormatFunc)efh_image }, { (gchar *) "image/pjpeg", (EMFormatFunc)efh_image }, +#endif /* special internal types */ diff --git a/plugins/image-inline/Makefile.am b/plugins/image-inline/Makefile.am new file mode 100644 index 0000000000..5ff7c260eb --- /dev/null +++ b/plugins/image-inline/Makefile.am @@ -0,0 +1,29 @@ +@EVO_PLUGIN_RULE@ + +plugin_DATA = org-gnome-image-inline.eplug + +plugin_LTLIBRARIES = liborg-gnome-image-inline.la + +liborg_gnome_image_inline_la_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir) \ + $(GNOME_PLATFORM_CFLAGS) \ + $(EVOLUTION_MAIL_CFLAGS) \ + $(GTKIMAGEVIEW_CFLAGS) + +liborg_gnome_image_inline_la_SOURCES = image-inline.c + +liborg_gnome_image_inline_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) + +liborg_gnome_image_inline_la_LIBADD = \ + $(top_builddir)/mail/libevolution-mail.la \ + $(GTKIMAGEVIEW_LIBS) \ + $(EVOLUTION_MAIL_LIBS) \ + $(GNOME_PLATFORM_LIBS) + +EXTRA_DIST = org-gnome-image-inline.eplug.xml + +BUILT_SOURCES = $(plugin_DATA) +CLEANFILES = $(BUILT_SOURCES) + +-include $(top_srcdir)/git.mk diff --git a/plugins/image-inline/image-inline.c b/plugins/image-inline/image-inline.c new file mode 100644 index 0000000000..81e5d92c5e --- /dev/null +++ b/plugins/image-inline/image-inline.c @@ -0,0 +1,219 @@ +/* + * image-inline.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) + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "mail/em-format-hook.h" +#include "mail/em-format-html.h" + +static gint org_gnome_image_inline_classid; + +/* Forward Declarations */ +void org_gnome_image_inline_format (gpointer ep, EMFormatHookTarget *target); + +typedef struct _ImageInlinePObject ImageInlinePObject; + +struct _ImageInlinePObject { + EMFormatHTMLPObject object; + + GdkPixbuf *pixbuf; + GtkWidget *widget; +}; + +static void +size_allocate_cb (GtkHTMLEmbedded *embedded, + GtkAllocation *event, + ImageInlinePObject *image_object) +{ + GtkWidget *widget; + gint pixbuf_width; + gint pixbuf_height; + gint widget_width; + gint widget_height; + gdouble zoom; + + widget = GTK_WIDGET (image_object->object.format->html); + widget_width = widget->allocation.width - 12; + + pixbuf_width = gdk_pixbuf_get_width (image_object->pixbuf); + pixbuf_height = gdk_pixbuf_get_height (image_object->pixbuf); + + if (pixbuf_width <= widget_width) + zoom = 1.0; + else + zoom = (gdouble) widget_width / pixbuf_width; + + widget_width = MIN (widget_width, pixbuf_width); + widget_height = (gint) (zoom * pixbuf_height); + + gtk_widget_set_size_request ( + image_object->widget, widget_width, widget_height); +} + +static void +org_gnome_image_inline_pobject_free (EMFormatHTMLPObject *object) +{ + ImageInlinePObject *image_object; + + image_object = (ImageInlinePObject *) object; + + if (image_object->pixbuf != NULL) { + g_object_unref (image_object->pixbuf); + image_object->pixbuf = NULL; + } + + if (image_object->widget != NULL) { + g_object_unref (image_object->widget); + image_object->widget = NULL; + } +} + +static void +org_gnome_image_inline_decode (ImageInlinePObject *image_object, + CamelMimePart *mime_part) +{ + GdkPixbuf *pixbuf; + GdkPixbufLoader *loader; + CamelContentType *content_type; + CamelDataWrapper *data_wrapper; + CamelMedium *medium; + CamelStream *stream; + GByteArray *array; + gchar *mime_type; + GError *error = NULL; + + array = g_byte_array_new (); + medium = CAMEL_MEDIUM (mime_part); + + /* Stream takes ownership of the byte array. */ + stream = camel_stream_mem_new_with_byte_array (array); + data_wrapper = camel_medium_get_content_object (medium); + camel_data_wrapper_decode_to_stream (data_wrapper, stream); + + content_type = camel_mime_part_get_content_type (mime_part); + mime_type = camel_content_type_simple (content_type); + loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error); + g_free (mime_type); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + goto exit; + } + + gdk_pixbuf_loader_write (loader, array->data, array->len, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + goto exit; + } + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf != NULL) + image_object->pixbuf = g_object_ref (pixbuf); + + gdk_pixbuf_loader_close (loader, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + goto exit; + } + +exit: + camel_object_unref (mime_part); + camel_object_unref (stream); +} + +static gboolean +org_gnome_image_inline_embed (EMFormatHTML *format, + GtkHTMLEmbedded *embedded, + EMFormatHTMLPObject *object) +{ + ImageInlinePObject *image_object; + GtkImageView *image_view; + GtkWidget *container; + GtkWidget *widget; + + image_object = (ImageInlinePObject *) object; + + if (image_object->pixbuf == NULL) + return FALSE; + + container = GTK_WIDGET (embedded); + + widget = gtk_image_view_new (); + image_view = GTK_IMAGE_VIEW (widget); + gtk_widget_show (widget); + + widget = gtk_image_scroll_win_new (image_view); + gtk_container_add (GTK_CONTAINER (container), widget); + image_object->widget = g_object_ref (widget); + gtk_widget_show (widget); + + gtk_image_view_set_pixbuf ( + image_view, image_object->pixbuf, TRUE); + + g_signal_connect ( + embedded, "size-allocate", + G_CALLBACK (size_allocate_cb), image_object); + + return TRUE; +} + +void +org_gnome_image_inline_format (gpointer ep, EMFormatHookTarget *target) +{ + ImageInlinePObject *image_object; + gchar *classid; + + classid = g_strdup_printf ( + "org-gnome-image-inline-display-%d", + org_gnome_image_inline_classid++); + + image_object = (ImageInlinePObject *) + em_format_html_add_pobject ( + EM_FORMAT_HTML (target->format), + sizeof (ImageInlinePObject), + classid, target->part, + org_gnome_image_inline_embed); + + camel_object_ref (target->part); + + image_object->object.free = org_gnome_image_inline_pobject_free; + org_gnome_image_inline_decode (image_object, target->part); + + camel_stream_printf ( + target->stream, "", classid); + + g_free (classid); +} diff --git a/plugins/image-inline/org-gnome-image-inline.eplug.xml b/plugins/image-inline/org-gnome-image-inline.eplug.xml new file mode 100644 index 0000000000..581d43b46c --- /dev/null +++ b/plugins/image-inline/org-gnome-image-inline.eplug.xml @@ -0,0 +1,125 @@ + + + + + + <_description> + View image attachments directly in mail messages. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3