aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2009-11-08 14:49:48 +0800
committerMatthew Barnes <mbarnes@redhat.com>2009-11-10 08:57:12 +0800
commite13eb8a5b52c0b95f5b235c61245277230d565dc (patch)
tree8cf00d8bb9927c301029725e8e4009ba84c6df1f
parent6db0e254190a80cf1cccb3629442b78e76c55b36 (diff)
downloadgsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.tar
gsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.tar.gz
gsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.tar.bz2
gsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.tar.lz
gsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.tar.xz
gsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.tar.zst
gsoc2013-evolution-e13eb8a5b52c0b95f5b235c61245277230d565dc.zip
Add zooming and drag-and-drop to the plugin.
A bunch of crusty old code in em-format-html-display.c falls out.
-rw-r--r--mail/Makefile.am2
-rw-r--r--mail/em-format-html-display.c277
-rw-r--r--mail/em-format-html-display.h4
-rw-r--r--mail/em-format-html.c4
-rw-r--r--mail/em-icon-stream.c347
-rw-r--r--mail/em-icon-stream.h61
-rw-r--r--plugins/image-inline/Makefile.am1
-rw-r--r--plugins/image-inline/image-inline.c165
8 files changed, 151 insertions, 710 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 7f284e96e2..01d41aaaa6 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -70,7 +70,6 @@ mailinclude_HEADERS = \
em-format-html-display.h \
em-format-html-print.h \
em-html-stream.h \
- em-icon-stream.h \
em-inline-filter.h \
em-junk.h \
em-search-context.h \
@@ -127,7 +126,6 @@ libevolution_mail_la_SOURCES = \
em-format-html-display.c \
em-format-html-print.c \
em-html-stream.c \
- em-icon-stream.c \
em-inline-filter.c \
em-junk.c \
em-search-context.c \
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index de64e2b15c..34c146e05f 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -76,7 +76,6 @@
#include "e-mail-display.h"
#include "e-mail-attachment-bar.h"
#include "em-format-html-display.h"
-#include "em-icon-stream.h"
#include "em-utils.h"
#include "widgets/misc/e-attachment-button.h"
#include "widgets/misc/e-attachment-view.h"
@@ -126,7 +125,6 @@ static const gchar *smime_sign_colour[5] = {
};
static void efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri);
-static gboolean efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
static void efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
static gboolean efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject);
static gboolean efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *object);
@@ -672,58 +670,7 @@ em_format_html_display_new (void)
/* ********************************************************************** */
-static void
-efhd_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *handle)
-{
- gchar *classid;
- struct _attach_puri *info;
-
- classid = g_strdup_printf("image%s", ((EMFormat *)efh)->part_id->str);
- info = (struct _attach_puri *)em_format_add_puri((EMFormat *)efh, sizeof(*info), classid, part, efhd_attachment_frame);
- em_format_html_add_pobject(efh, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_image);
-
- info->handle = handle;
- info->shown = TRUE;
- info->snoop_mime_type = ((EMFormat *) efh)->snoop_mime_type;
- if (camel_operation_cancel_check (NULL) || !info->puri.format || !((EMFormatHTML *)info->puri.format)->html) {
- /* some fake value, we are cancelled anyway, thus doesn't matter */
- info->fit_width = 256;
- } else {
- info->fit_width = ((GtkWidget *)((EMFormatHTML *)info->puri.format)->html)->allocation.width - 12;
- }
-
- camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid);
- g_free(classid);
-}
-
-/* ********************************************************************** */
-
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 },
- { (gchar *) "image/x-png", (EMFormatFunc)efhd_image },
- { (gchar *) "image/tiff", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-bmp", (EMFormatFunc)efhd_image },
- { (gchar *) "image/bmp", (EMFormatFunc)efhd_image },
- { (gchar *) "image/svg", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-cmu-raster", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-ico", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-portable-anymap", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-portable-bitmap", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-portable-graymap", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-portable-pixmap", (EMFormatFunc)efhd_image },
- { (gchar *) "image/x-xpixmap", (EMFormatFunc)efhd_image },
-
- /* This is where one adds those busted, non-registered types,
- that some idiot mailer writers out there decide to pull out
- of their proverbials at random. */
-
- { (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 }
};
@@ -839,219 +786,6 @@ efhd_attachment_button_expanded (GtkWidget *widget,
/* ********************************************************************** */
-static void
-efhd_drag_data_get(GtkWidget *w, GdkDragContext *drag, GtkSelectionData *data, guint info, guint time, EMFormatHTMLPObject *pobject)
-{
- CamelMimePart *part = pobject->part;
- gchar *uri, *uri_crlf, *path;
- CamelStream *stream;
-
- switch (info) {
- case 0: /* mime/type request */
- stream = camel_stream_mem_new();
- /* TODO: shoudl format_format_text run on the content-object? */
- /* TODO: should we just do format_content? */
- if (camel_content_type_is (((CamelDataWrapper *)part)->mime_type, "text", "*")) {
- /* FIXME: this should be an em_utils method, it only needs a default charset param */
- em_format_format_text((EMFormat *)pobject->format, stream, (CamelDataWrapper *)part);
- } else {
- CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
-
- camel_data_wrapper_decode_to_stream(dw, stream);
- }
-
- gtk_selection_data_set(data, data->target, 8,
- ((CamelStreamMem *)stream)->buffer->data,
- ((CamelStreamMem *)stream)->buffer->len);
- camel_object_unref(stream);
- break;
- case 1: /* text-uri-list request */
- /* Kludge around Nautilus requesting the same data many times */
- uri = g_object_get_data((GObject *)w, "e-drag-uri");
- if (uri) {
- gtk_selection_data_set(data, data->target, 8, (guchar *)uri, strlen(uri));
- return;
- }
-
- path = em_utils_temp_save_part(w, part, FALSE);
- if (path == NULL)
- return;
-
- uri = g_filename_to_uri(path, NULL, NULL);
- g_free(path);
- uri_crlf = g_strconcat(uri, "\r\n", NULL);
- g_free(uri);
- gtk_selection_data_set(data, data->target, 8, (guchar *)uri_crlf, strlen(uri_crlf));
- g_object_set_data_full((GObject *)w, "e-drag-uri", uri_crlf, g_free);
- break;
- default:
- abort();
- }
-}
-
-static void
-efhd_drag_data_delete(GtkWidget *w, GdkDragContext *drag, EMFormatHTMLPObject *pobject)
-{
- gchar *uri;
-
- uri = g_object_get_data((GObject *)w, "e-drag-uri");
- if (uri) {
- /* NB: this doesn't kill the dnd directory */
- /* NB: is this ever called? */
- /* NB even more: doesn't the e-drag-uri have \r\n
- * appended? (see efhd_drag_data_get())
- */
- gchar *filename = g_filename_from_uri (uri, NULL, NULL);
- g_unlink(filename);
- g_free(filename);
- g_object_set_data((GObject *)w, "e-drag-uri", NULL);
- }
-}
-
-static void
-efhd_write_icon_job(struct _EMFormatHTMLJob *job, gint cancelled)
-{
- EMFormatHTMLPObject *pobject;
- CamelDataWrapper *dw;
-
- if (cancelled)
- return;
-
- pobject = job->u.data;
- dw = camel_medium_get_content_object((CamelMedium *)pobject->part);
- camel_data_wrapper_decode_to_stream(dw, job->stream);
- camel_stream_close(job->stream);
-}
-
-static void
-efhd_image_resized(GtkWidget *w, GtkAllocation *event, struct _attach_puri *info)
-{
- GdkPixbuf *pb;
- gint width;
-
- if (info->fit_width == 0)
- return;
-
- width = ((GtkWidget *)((EMFormatHTML *)info->puri.format)->html)->allocation.width - 12;
- if (info->fit_width == width)
- return;
- info->fit_width = width;
-
- pb = em_icon_stream_get_image(info->puri.cid, info->fit_width, info->fit_height);
- if (pb) {
- gtk_image_set_from_pixbuf(info->image, pb);
- g_object_unref(pb);
- }
-}
-
-static void
-efhd_change_cursor(GtkWidget *w, GdkEventCrossing *event, struct _attach_puri *info)
-{
- if (info->shown && info->image) {
- if (info->fit_width != 0) {
- if (em_icon_stream_is_resized(info->puri.cid, info->fit_width, info->fit_height))
- e_cursor_set(w->window, E_CURSOR_ZOOM_IN);
-
- }
- }
-}
-
-static void
-efhd_image_fit_width(GtkWidget *widget, GdkEventButton *event, struct _attach_puri *info)
-{
- gint width;
-
- width = ((GtkWidget *)((EMFormatHTML *)info->puri.format)->html)->allocation.width - 12;
-
- if (info->shown && info->image) {
- if (info->fit_width != 0) {
- if (em_icon_stream_is_resized(info->puri.cid, info->fit_width, info->fit_height)) {
- if (info->fit_width != width) {
- info->fit_width = width;
- e_cursor_set (widget->window, E_CURSOR_ZOOM_IN);
- } else {
- info->fit_width = 0;
- e_cursor_set(widget->window, E_CURSOR_ZOOM_OUT);
- }
- }
- } else {
- info->fit_width = width;
- e_cursor_set (widget->window, E_CURSOR_ZOOM_IN);
- }
- }
-
- gtk_image_set_from_pixbuf(info->image, em_icon_stream_get_image(info->puri.cid, info->fit_width, info->fit_height));
-}
-
-/* When the puri gets freed in the formatter thread and if the image is resized, crash will happen
- See bug #333864 So while freeing the puri, we disconnect the image attach resize attached with
- the puri */
-
-static void
-efhd_image_unallocate (struct _EMFormatPURI * puri)
-{
- struct _attach_puri *info = (struct _attach_puri *) puri;
- g_signal_handlers_disconnect_by_func(info->html, efhd_image_resized, info);
-
- g_signal_handlers_disconnect_by_func(info->event_box, efhd_change_cursor, info);
- g_signal_handlers_disconnect_by_func(info->event_box, efhd_image_fit_width, info);
-}
-
-static gboolean
-efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
-{
- GtkWidget *box;
- EMFormatHTMLJob *job;
- struct _attach_puri *info;
- GdkPixbuf *pixbuf;
- GtkTargetEntry drag_types[] = {
- { NULL, 0, 0 },
- { (gchar *) "text/uri-list", 0, 1 },
- };
- gchar *simple_type;
-
- info = (struct _attach_puri *)em_format_find_puri((EMFormat *)efh, pobject->classid);
-
- info->image = (GtkImage *)gtk_image_new();
- info->html = eb;
- info->puri.free = efhd_image_unallocate;
-
- pixbuf = em_icon_stream_get_image(pobject->classid, info->fit_width, info->fit_height);
- if (pixbuf) {
- gtk_image_set_from_pixbuf(info->image, pixbuf);
- g_object_unref(pixbuf);
- } else {
- job = em_format_html_job_new(efh, efhd_write_icon_job, pobject);
- job->stream = (CamelStream *)em_icon_stream_new((GtkImage *)info->image, pobject->classid, info->fit_width, info->fit_height, TRUE);
- em_format_html_job_queue(efh, job);
- }
-
- box = gtk_event_box_new();
- info->event_box = box;
- gtk_container_add((GtkContainer *)box, (GtkWidget *)info->image);
- gtk_widget_show_all(box);
- gtk_container_add((GtkContainer *)eb, box);
-
- g_signal_connect(eb, "size_allocate", G_CALLBACK(efhd_image_resized), info);
-
- simple_type = camel_content_type_simple(((CamelDataWrapper *)pobject->part)->mime_type);
- camel_strdown(simple_type);
-
- drag_types[0].target = simple_type;
- gtk_drag_source_set(box, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS (drag_types), GDK_ACTION_COPY);
- g_free(simple_type);
-
- g_signal_connect(box, "drag-data-get", G_CALLBACK(efhd_drag_data_get), pobject);
- g_signal_connect (box, "drag-data-delete", G_CALLBACK(efhd_drag_data_delete), pobject);
-
- g_signal_connect(box, "enter-notify-event", G_CALLBACK(efhd_change_cursor), info);
- g_signal_connect(box, "button-press-event", G_CALLBACK(efhd_image_fit_width), info);
-
- g_object_set_data (G_OBJECT (box), "efh", efh);
-
- return TRUE;
-}
-
/* attachment button callback */
static gboolean
efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
@@ -1083,8 +817,8 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
parent = gtk_widget_get_toplevel (GTK_WIDGET (efh->html));
parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
- view = E_ATTACHMENT_VIEW (efhd->priv->attachment_view);
- gtk_widget_show (efhd->priv->attachment_view);
+ view = em_format_html_display_get_attachment_view (efhd);
+ gtk_widget_show (GTK_WIDGET (view));
store = e_attachment_view_get_store (view);
e_attachment_store_add_attachment (store, info->attachment);
@@ -1298,3 +1032,10 @@ efhd_attachment_optional(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPOb
return TRUE;
}
+EAttachmentView *
+em_format_html_display_get_attachment_view (EMFormatHTMLDisplay *html_display)
+{
+ g_return_val_if_fail (EM_IS_FORMAT_HTML_DISPLAY (html_display), NULL);
+
+ return E_ATTACHMENT_VIEW (html_display->priv->attachment_view);
+}
diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h
index 4626598cb5..089b361592 100644
--- a/mail/em-format-html-display.h
+++ b/mail/em-format-html-display.h
@@ -26,6 +26,7 @@
#define EM_FORMAT_HTML_DISPLAY_H
#include <mail/em-format-html.h>
+#include <misc/e-attachment-view.h>
/* Standard GObject macros */
#define EM_TYPE_FORMAT_HTML_DISPLAY \
@@ -66,6 +67,9 @@ struct _EMFormatHTMLDisplayClass {
GType em_format_html_display_get_type (void);
EMFormatHTMLDisplay *
em_format_html_display_new (void);
+EAttachmentView *
+ em_format_html_display_get_attachment_view
+ (EMFormatHTMLDisplay *html_display);
G_END_DECLS
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 29bb47653f..47213dc5d5 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -2105,7 +2105,6 @@ 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 },
@@ -2121,7 +2120,6 @@ 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 },
@@ -2135,10 +2133,8 @@ 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/mail/em-icon-stream.c b/mail/em-icon-stream.c
deleted file mode 100644
index 563853adcf..0000000000
--- a/mail/em-icon-stream.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * 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/>
- *
- *
- * Authors:
- * Jeffrey Stedfast <fejj@ximian.com>
- * Michael Zucchi <notzed@ximian.com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gtk/gtk.h>
-#include "em-icon-stream.h"
-#include "e-util/e-icon-factory.h"
-
-#include "libedataserver/e-msgport.h"
-
-#define d(x)
-
-/* fixed-point scale factor for scaled images in cache */
-#define EMIS_SCALE (1024)
-
-struct _emis_cache_node {
- EMCacheNode node;
-
- GdkPixbuf *pixbuf;
-};
-
-static void em_icon_stream_class_init (EMIconStreamClass *klass);
-static void em_icon_stream_init (CamelObject *object);
-static void em_icon_stream_finalize (CamelObject *object);
-
-static gssize emis_sync_write(CamelStream *stream, const gchar *buffer, gsize n);
-static gint emis_sync_close(CamelStream *stream);
-static gint emis_sync_flush(CamelStream *stream);
-
-static EMSyncStreamClass *parent_class = NULL;
-static EMCache *emis_cache;
-
-static void
-emis_cache_free(gpointer data)
-{
- struct _emis_cache_node *node = data;
-
- g_object_unref(node->pixbuf);
-}
-
-CamelType
-em_icon_stream_get_type (void)
-{
- static CamelType type = CAMEL_INVALID_TYPE;
-
- if (type == CAMEL_INVALID_TYPE) {
- parent_class = (EMSyncStreamClass *)em_sync_stream_get_type();
- type = camel_type_register (em_sync_stream_get_type(),
- "EMIconStream",
- sizeof (EMIconStream),
- sizeof (EMIconStreamClass),
- (CamelObjectClassInitFunc) em_icon_stream_class_init,
- NULL,
- (CamelObjectInitFunc) em_icon_stream_init,
- (CamelObjectFinalizeFunc) em_icon_stream_finalize);
-
- emis_cache = em_cache_new(60, sizeof(struct _emis_cache_node), emis_cache_free);
- }
-
- return type;
-}
-
-static void
-em_icon_stream_class_init (EMIconStreamClass *klass)
-{
- ((EMSyncStreamClass *)klass)->sync_write = emis_sync_write;
- ((EMSyncStreamClass *)klass)->sync_flush = emis_sync_flush;
- ((EMSyncStreamClass *)klass)->sync_close = emis_sync_close;
-}
-
-static void
-em_icon_stream_init (CamelObject *object)
-{
- EMIconStream *emis = (EMIconStream *)object;
-
- emis = emis;
-}
-
-static void
-emis_cleanup(EMIconStream *emis)
-{
- if (emis->loader) {
- gdk_pixbuf_loader_close(emis->loader, NULL);
- g_object_unref(emis->loader);
- emis->loader = NULL;
- }
-
- if (emis->destroy_id) {
- g_signal_handler_disconnect(emis->image, emis->destroy_id);
- emis->destroy_id = 0;
- }
-
- g_free(emis->key);
- emis->key = NULL;
-
- emis->image = NULL;
- emis->sync.cancel = TRUE;
-}
-
-static void
-em_icon_stream_finalize(CamelObject *object)
-{
- EMIconStream *emis = (EMIconStream *)object;
-
- emis_cleanup(emis);
-}
-
-static gssize
-emis_sync_write(CamelStream *stream, const gchar *buffer, gsize n)
-{
- EMIconStream *emis = EM_ICON_STREAM (stream);
-
- if (emis->loader == NULL)
- return -1;
-
- if (!gdk_pixbuf_loader_write(emis->loader, (const guchar *)buffer, n, NULL)) {
- emis_cleanup(emis);
- return -1;
- }
-
- return (gssize) n;
-}
-
-static gint
-emis_sync_flush(CamelStream *stream)
-{
- return 0;
-}
-
-static GdkPixbuf *
-emis_fit(GdkPixbuf *pixbuf, gint maxwidth, gint maxheight, gint *scale)
-{
- GdkPixbuf *mini = NULL;
- gint width, height;
-
- width = gdk_pixbuf_get_width(pixbuf);
- height = gdk_pixbuf_get_height(pixbuf);
-
- if ((maxwidth && width > maxwidth)
- || (maxheight && height > maxheight)) {
- if (width >= height || maxheight == 0) {
- if (scale)
- *scale = maxwidth * EMIS_SCALE / width;
- height = height * maxwidth / width;
- width = maxwidth;
- } else {
- if (scale)
- *scale = maxheight * EMIS_SCALE / height;
- width = width * maxheight / height;
- height = maxheight;
- }
-
- /* check if we don't want to scale down too much, if so, do 1 pixel width/height */
- if (width <= 0)
- width = 1;
-
- if (height <= 0)
- height = 1;
-
- mini = e_icon_factory_pixbuf_scale (pixbuf, width, height);
- }
-
- return mini;
-}
-
-static gint
-emis_sync_close(CamelStream *stream)
-{
- EMIconStream *emis = (EMIconStream *)stream;
- GdkPixbuf *pixbuf, *mini;
- struct _emis_cache_node *node;
- gchar *scalekey;
- gint scale;
-
- if (emis->loader == NULL)
- return -1;
-
- gdk_pixbuf_loader_close(emis->loader, NULL);
-
- pixbuf = gdk_pixbuf_loader_get_pixbuf(emis->loader);
- if (pixbuf == NULL) {
- d(printf("couldn't get pixbuf from loader\n"));
- emis_cleanup(emis);
- return -1;
- }
-
- mini = emis_fit(pixbuf, emis->width, emis->height, &scale);
- gtk_image_set_from_pixbuf(emis->image, mini?mini:pixbuf);
-
- if (emis->keep) {
- node = (struct _emis_cache_node *)em_cache_node_new(emis_cache, emis->key);
- node->pixbuf = g_object_ref(pixbuf);
- em_cache_add(emis_cache, (EMCacheNode *)node);
- }
-
- if (!emis->keep || mini) {
- scalekey = g_alloca(strlen(emis->key) + 20);
- sprintf(scalekey, "%s.%x", emis->key, scale);
- node = (struct _emis_cache_node *)em_cache_node_new(emis_cache, scalekey);
- node->pixbuf = mini?mini:g_object_ref(pixbuf);
- em_cache_add(emis_cache, (EMCacheNode *)node);
- }
-
- g_object_unref(emis->loader);
- emis->loader = NULL;
-
- g_signal_handler_disconnect(emis->image, emis->destroy_id);
- emis->destroy_id = 0;
-
- return 0;
-}
-
-static void
-emis_image_destroy(GtkImage *image, EMIconStream *emis)
-{
- emis_cleanup(emis);
-}
-
-CamelStream *
-em_icon_stream_new(GtkImage *image, const gchar *key, guint maxwidth, guint maxheight, gint keep)
-{
- EMIconStream *new;
-
- new = EM_ICON_STREAM(camel_object_new(EM_ICON_STREAM_TYPE));
- new->width = maxwidth;
- new->height = maxheight;
- new->image = image;
- new->keep = keep;
- new->destroy_id = g_signal_connect(image, "destroy", G_CALLBACK(emis_image_destroy), new);
- new->loader = gdk_pixbuf_loader_new();
- new->key = g_strdup(key);
-
- return (CamelStream *)new;
-}
-
-GdkPixbuf *
-em_icon_stream_get_image(const gchar *tkey, guint maxwidth, guint maxheight)
-{
- struct _emis_cache_node *node;
- GdkPixbuf *pb = NULL;
- const gchar *key;
-
- key = tkey ? tkey : "";
-
- /* forces the cache to be setup if not */
- em_icon_stream_get_type();
-
- node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, key);
- if (node) {
- gint width, height;
-
- pb = node->pixbuf;
- g_object_ref(pb);
- em_cache_node_unref(emis_cache, (EMCacheNode *)node);
-
- width = gdk_pixbuf_get_width(pb);
- height = gdk_pixbuf_get_height(pb);
-
- if ((maxwidth && width > maxwidth)
- || (maxheight && height > maxheight)) {
- guint scale;
- gchar *realkey;
-
- if (maxheight == 0 || width >= height)
- scale = width * EMIS_SCALE / maxwidth;
- else
- scale = height * EMIS_SCALE / maxheight;
-
- realkey = g_alloca(strlen(key)+20);
- sprintf(realkey, "%s.%x", key, scale);
- node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, realkey);
- if (node) {
- g_object_unref(pb);
- pb = node->pixbuf;
- g_object_ref(pb);
- em_cache_node_unref(emis_cache, (EMCacheNode *)node);
- } else {
- GdkPixbuf *mini = emis_fit(pb, maxwidth, maxheight, NULL);
-
- g_object_unref(pb);
- pb = mini;
- node = (struct _emis_cache_node *)em_cache_node_new(emis_cache, realkey);
- node->pixbuf = pb;
- g_object_ref(pb);
- em_cache_add(emis_cache, (EMCacheNode *)node);
- }
- }
- }
-
- return pb;
-}
-
-gint
-em_icon_stream_is_resized(const gchar *tkey, guint maxwidth, guint maxheight)
-{
- gint res = FALSE;
- struct _emis_cache_node *node;
- const gchar *key;
-
- key = tkey ? tkey : "";
-
- /* forces the cache to be setup if not */
- em_icon_stream_get_type();
-
- node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, key);
- if (node) {
- res = (maxwidth && gdk_pixbuf_get_width(node->pixbuf) > maxwidth)
- || (maxheight && gdk_pixbuf_get_width(node->pixbuf) > maxheight);
-
- em_cache_node_unref(emis_cache, (EMCacheNode *)node);
- }
-
- return res;
-}
-
-void
-em_icon_stream_clear_cache(void)
-{
- em_cache_clear(emis_cache);
-}
diff --git a/mail/em-icon-stream.h b/mail/em-icon-stream.h
deleted file mode 100644
index a06b30d4de..0000000000
--- a/mail/em-icon-stream.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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/>
- *
- *
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifndef EM_ICON_STREAM_H
-#define EM_ICON_STREAM_H
-
-#include "mail/em-sync-stream.h"
-
-#define EM_ICON_STREAM_TYPE (em_icon_stream_get_type ())
-#define EM_ICON_STREAM(obj) (CAMEL_CHECK_CAST((obj), EM_ICON_STREAM_TYPE, EMIconStream))
-#define EM_ICON_STREAM_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), EM_ICON_STREAM_TYPE, EMIconStreamClass))
-#define EM_IS_ICON_STREAM(o) (CAMEL_CHECK_TYPE((o), EM_ICON_STREAM_TYPE))
-
-G_BEGIN_DECLS
-
-typedef struct _EMIconStream {
- EMSyncStream sync;
-
- guint width, height;
- guint destroy_id;
- struct _GdkPixbufLoader *loader;
- GtkImage *image;
- gchar *key;
-
- guint keep:1;
-} EMIconStream;
-
-typedef struct {
- EMSyncStreamClass parent_class;
-} EMIconStreamClass;
-
-CamelType em_icon_stream_get_type (void);
-CamelStream *em_icon_stream_new(GtkImage *image, const gchar *key, guint maxwidth, guint maxheight, gint keep);
-
-struct _GdkPixbuf *em_icon_stream_get_image(const gchar *key, guint maxwidth, guint maxheight);
-gint em_icon_stream_is_resized(const gchar *key, guint maxwidth, guint maxheight);
-
-void em_icon_stream_clear_cache(void);
-
-G_END_DECLS
-
-#endif /* EM_ICON_STREAM_H */
diff --git a/plugins/image-inline/Makefile.am b/plugins/image-inline/Makefile.am
index 5ff7c260eb..d59203a79b 100644
--- a/plugins/image-inline/Makefile.am
+++ b/plugins/image-inline/Makefile.am
@@ -7,6 +7,7 @@ plugin_LTLIBRARIES = liborg-gnome-image-inline.la
liborg_gnome_image_inline_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir) \
+ -I$(top_srcdir)/widgets \
$(GNOME_PLATFORM_CFLAGS) \
$(EVOLUTION_MAIL_CFLAGS) \
$(GTKIMAGEVIEW_CFLAGS)
diff --git a/plugins/image-inline/image-inline.c b/plugins/image-inline/image-inline.c
index 81e5d92c5e..688a7d7d17 100644
--- a/plugins/image-inline/image-inline.c
+++ b/plugins/image-inline/image-inline.c
@@ -31,8 +31,8 @@
#include <gtkhtml/gtkhtml-embedded.h>
#include <gtkimageview/gtkimagescrollwin.h>
-#include "mail/em-format-hook.h"
-#include "mail/em-format-html.h"
+#include <mail/em-format-hook.h>
+#include <mail/em-format-html-display.h>
static gint org_gnome_image_inline_classid;
@@ -44,13 +44,118 @@ typedef struct _ImageInlinePObject ImageInlinePObject;
struct _ImageInlinePObject {
EMFormatHTMLPObject object;
+ CamelMimePart *mime_part;
GdkPixbuf *pixbuf;
GtkWidget *widget;
};
static void
+set_drag_source (GtkImageView *image_view)
+{
+ GtkTargetEntry *targets;
+ GtkTargetList *list;
+ gint n_targets;
+
+ list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_uri_targets (list, 0);
+ targets = gtk_target_table_new_from_list (list, &n_targets);
+
+ gtk_drag_source_set (
+ GTK_WIDGET (image_view), GDK_BUTTON1_MASK,
+ targets, n_targets, GDK_ACTION_COPY);
+
+ gtk_target_table_free (targets, n_targets);
+ gtk_target_list_unref (list);
+}
+
+static gboolean
+button_press_press_cb (GtkImageView *image_view,
+ GdkEventButton *event,
+ ImageInlinePObject *image_object)
+{
+ if (event->type != GDK_2BUTTON_PRESS)
+ return FALSE;
+
+ if (gtk_image_view_get_zoom (image_view) < 1.0) {
+ gtk_image_view_set_zoom (image_view, 1.0);
+ gtk_drag_source_unset (GTK_WIDGET (image_view));
+ } else {
+ gtk_image_view_set_fitting (image_view, TRUE);
+ set_drag_source (image_view);
+ }
+
+ return TRUE;
+}
+
+static void
+drag_data_get_cb (GtkImageView *image_view,
+ GdkDragContext *context,
+ GtkSelectionData *selection,
+ guint info,
+ guint time,
+ ImageInlinePObject *image_object)
+{
+ EMFormatHTMLDisplay *html_display;
+ EAttachmentStore *store;
+ EAttachmentView *view;
+ EAttachment *attachment = NULL;
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
+ GList *list, *iter;
+
+ /* XXX This illustrates the lack of integration between EMFormat
+ * and EAttachment, in that we now have to search through the
+ * attachment store to find an attachment whose CamelMimePart
+ * matches ours. This allows us to defer to EAttachmentView
+ * for the drag-data-get implementation. */
+
+ html_display = EM_FORMAT_HTML_DISPLAY (image_object->object.format);
+ view = em_format_html_display_get_attachment_view (html_display);
+
+ store = e_attachment_view_get_store (view);
+ list = e_attachment_store_get_attachments (store);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ CamelMimePart *mime_part;
+
+ attachment = E_ATTACHMENT (iter->data);
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ if (mime_part == image_object->mime_part) {
+ g_object_ref (attachment);
+ break;
+ }
+
+ attachment = NULL;
+ }
+
+ g_list_foreach (list, (GFunc) g_object_unref, NULL);
+ g_list_free (list);
+
+ /* Make sure we found an EAttachment to select. */
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ /* Now select its path in the attachment store. */
+
+ reference = e_attachment_get_reference (attachment);
+ g_return_if_fail (gtk_tree_row_reference_valid (reference));
+
+ path = gtk_tree_row_reference_get_path (reference);
+
+ e_attachment_view_unselect_all (view);
+ e_attachment_view_select_path (view, path);
+
+ gtk_tree_path_free (path);
+
+ /* Let EAttachmentView handle the rest. */
+
+ e_attachment_view_drag_data_get (
+ view, context, selection, info, time);
+}
+
+static void
size_allocate_cb (GtkHTMLEmbedded *embedded,
- GtkAllocation *event,
+ GtkAllocation *allocation,
ImageInlinePObject *image_object)
{
GtkWidget *widget;
@@ -58,7 +163,7 @@ size_allocate_cb (GtkHTMLEmbedded *embedded,
gint pixbuf_height;
gint widget_width;
gint widget_height;
- gdouble zoom;
+ gdouble zoom = 1.0;
widget = GTK_WIDGET (image_object->object.format->html);
widget_width = widget->allocation.width - 12;
@@ -66,9 +171,7 @@ size_allocate_cb (GtkHTMLEmbedded *embedded,
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
+ if (pixbuf_width > widget_width)
zoom = (gdouble) widget_width / pixbuf_width;
widget_width = MIN (widget_width, pixbuf_width);
@@ -85,6 +188,11 @@ org_gnome_image_inline_pobject_free (EMFormatHTMLPObject *object)
image_object = (ImageInlinePObject *) object;
+ if (image_object->mime_part != NULL) {
+ camel_object_unref (image_object->mime_part);
+ image_object->mime_part = NULL;
+ }
+
if (image_object->pixbuf != NULL) {
g_object_unref (image_object->pixbuf);
image_object->pixbuf = NULL;
@@ -97,20 +205,19 @@ org_gnome_image_inline_pobject_free (EMFormatHTMLPObject *object)
}
static void
-org_gnome_image_inline_decode (ImageInlinePObject *image_object,
- CamelMimePart *mime_part)
+org_gnome_image_inline_decode (ImageInlinePObject *image_object)
{
GdkPixbuf *pixbuf;
GdkPixbufLoader *loader;
- CamelContentType *content_type;
CamelDataWrapper *data_wrapper;
+ CamelMimePart *mime_part;
CamelMedium *medium;
CamelStream *stream;
GByteArray *array;
- gchar *mime_type;
GError *error = NULL;
array = g_byte_array_new ();
+ mime_part = image_object->mime_part;
medium = CAMEL_MEDIUM (mime_part);
/* Stream takes ownership of the byte array. */
@@ -118,17 +225,10 @@ org_gnome_image_inline_decode (ImageInlinePObject *image_object,
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;
- }
-
+ /* Don't trust the content type in the MIME part. It could
+ * be lying or it could be "application/octet-stream". Let
+ * the GtkPixbufLoader figure it out. */
+ loader = gdk_pixbuf_loader_new ();
gdk_pixbuf_loader_write (loader, array->data, array->len, &error);
if (error != NULL) {
@@ -150,8 +250,8 @@ org_gnome_image_inline_decode (ImageInlinePObject *image_object,
}
exit:
- camel_object_unref (mime_part);
camel_object_unref (stream);
+ g_object_unref (loader);
}
static gboolean
@@ -172,17 +272,25 @@ org_gnome_image_inline_embed (EMFormatHTML *format,
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);
+ image_view = GTK_IMAGE_VIEW (widget);
+
gtk_image_view_set_pixbuf (
image_view, image_object->pixbuf, TRUE);
+ set_drag_source (image_view);
+
+ g_signal_connect (
+ image_view, "button-press-event",
+ G_CALLBACK (button_press_press_cb), image_object);
+
+ g_signal_connect (
+ image_view, "drag-data-get",
+ G_CALLBACK (drag_data_get_cb), image_object);
+
g_signal_connect (
embedded, "size-allocate",
G_CALLBACK (size_allocate_cb), image_object);
@@ -208,9 +316,10 @@ org_gnome_image_inline_format (gpointer ep, EMFormatHookTarget *target)
org_gnome_image_inline_embed);
camel_object_ref (target->part);
+ image_object->mime_part = target->part;
image_object->object.free = org_gnome_image_inline_pobject_free;
- org_gnome_image_inline_decode (image_object, target->part);
+ org_gnome_image_inline_decode (image_object);
camel_stream_printf (
target->stream, "<object classid=%s></object>", classid);