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. --- plugins/image-inline/image-inline.c | 219 ++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 plugins/image-inline/image-inline.c (limited to 'plugins/image-inline/image-inline.c') 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); +} -- cgit