From 54a2910f896626046666ffa8d88f052acdb5c201 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 25 Jan 2001 17:07:23 +0000 Subject: Check if a message part's content is available, and if it's not, queue a * mail-format.c (mail_content_loaded): Check if a message part's content is available, and if it's not, queue a thread that will load it and then queue an idle-handler redisplay of the message. (call_handler_function): Call mail_content_loaded() on the part and don't try to display it if it's currently offline. (get_data_wrapper_text): Simplify a bit * mail-display.c (mail_display_queue_redisplay): rename and make non-static. (mail_display_redisplay): Use a "new and improved" way of preserving the GtkHTML scroll location. ("new and improved" is code for "gross and hackish", but there should be a real interface for this eventually.) (on_url_requested): Use mail_content_loaded() and don't write out offline cid: URLs * mail-identify.c (mail_identify_mime_part): Use mail_content_loaded and don't try to identify the data if it's offline. svn path=/trunk/; revision=7813 --- mail/ChangeLog | 22 ++++++++++ mail/mail-display.c | 64 ++++++++++------------------ mail/mail-display.h | 1 + mail/mail-format.c | 117 ++++++++++++++++++++++++++++++++++++++++++++------- mail/mail-identify.c | 30 +++++++------ mail/mail.h | 3 +- 6 files changed, 167 insertions(+), 70 deletions(-) diff --git a/mail/ChangeLog b/mail/ChangeLog index 81d1a1c542..621935654a 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,25 @@ +2001-01-25 Dan Winship + + * mail-format.c (mail_content_loaded): Check if a message part's + content is available, and if it's not, queue a thread that will + load it and then queue an idle-handler redisplay of the message. + (call_handler_function): Call mail_content_loaded() on the part + and don't try to display it if it's currently offline. + (get_data_wrapper_text): Simplify a bit + + * mail-display.c (mail_display_queue_redisplay): rename and make + non-static. + (mail_display_redisplay): Use a "new and improved" way of + preserving the GtkHTML scroll location. ("new and improved" is + code for "gross and hackish", but there should be a real interface + for this eventually.) + (on_url_requested): Use mail_content_loaded() and don't write out + offline cid: URLs + + * mail-identify.c (mail_identify_mime_part): Use + mail_content_loaded and don't try to identify the data if it's + offline. + 2001-01-25 Christopher James Lahey * message-list.c: Made the message list pay attention to the diff --git a/mail/mail-display.c b/mail/mail-display.c index c585ec0eac..31ec089f46 100644 --- a/mail/mail-display.c +++ b/mail/mail-display.c @@ -32,13 +32,12 @@ #include #include #include +#include /* XXX */ #define PARENT_TYPE (gtk_vbox_get_type ()) static GtkObjectClass *mail_display_parent_class; -static void redisplay (MailDisplay *md, gboolean unscroll); - struct _PixbufLoader { MailDisplay *md; CamelDataWrapper *wrapper; /* The data */ @@ -186,12 +185,12 @@ idle_redisplay (gpointer data) MailDisplay *md = data; md->idle_id = 0; - redisplay (md, FALSE); + mail_display_redisplay (md, FALSE); return FALSE; } -static void -queue_redisplay (MailDisplay *md) +void +mail_display_queue_redisplay (MailDisplay *md) { if (!md->idle_id) { md->idle_id = g_idle_add_full (G_PRIORITY_LOW, idle_redisplay, @@ -212,7 +211,7 @@ on_link_clicked (GtkHTML *html, const char *url, gpointer user_data) else if (!strcmp (url, "x-evolution-decode-pgp:")) { g_datalist_set_data (md->data, "show_pgp", GINT_TO_POINTER (1)); - queue_redisplay (md); + mail_display_queue_redisplay (md); } else gnome_url_show (url); } @@ -301,7 +300,7 @@ inline_cb (GtkWidget *widget, gpointer user_data) else camel_mime_part_set_disposition (part, "inline"); - queue_redisplay (md); + mail_display_queue_redisplay (md); } static gboolean @@ -767,6 +766,8 @@ on_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *handle, g_return_if_fail (CAMEL_IS_MEDIUM (medium)); data = camel_medium_get_content_object (medium); + if (!mail_content_loaded (data, md)) + return; ba = g_byte_array_new (); stream_mem = camel_stream_mem_new_with_byte_array (ba); @@ -844,17 +845,24 @@ clear_data (CamelObject *object, gpointer event_data, gpointer user_data) g_datalist_clear (&data); } -static void -redisplay (MailDisplay *md, gboolean unscroll) +/** + * mail_display_redisplay: + * @mail_display: the mail display object + * @unscroll: specifies whether or not to lose current scroll + * + * Force a redraw of the message display. + **/ +void +mail_display_redisplay (MailDisplay *md, gboolean unscroll) { - GtkAdjustment *adj; - gfloat oldv = 0; + printf("redisplaying\n"); + md->stream = gtk_html_begin (GTK_HTML (md->html)); if (!unscroll) { - adj = e_scroll_frame_get_vadjustment (md->scroll); - oldv = adj->value; + /* This is a hack until there's a clean way to do this. */ + GTK_HTML (md->html)->engine->newPage = FALSE; } - md->stream = gtk_html_begin (GTK_HTML (md->html)); + mail_html_write (md->html, md->stream, "%s%s", HTML_HEADER, "\n"); if (md->current_message) { @@ -868,32 +876,6 @@ redisplay (MailDisplay *md, gboolean unscroll) mail_html_write (md->html, md->stream, "\n"); gtk_html_end (md->html, md->stream, GTK_HTML_STREAM_OK); md->stream = NULL; - - if (unscroll) { - adj = e_scroll_frame_get_hadjustment (md->scroll); - gtk_adjustment_set_value (adj, 0); - e_scroll_frame_set_hadjustment (md->scroll, adj); - } else { - adj = e_scroll_frame_get_vadjustment (md->scroll); - if (oldv < adj->upper) { - gtk_adjustment_set_value (adj, oldv); - e_scroll_frame_set_vadjustment (md->scroll, adj); - } - } -} - - -/** - * mail_display_redisplay: - * @mail_display: the mail display object - * @unscroll: specifies whether or not to lose current scroll - * - * Force a redraw of the message display. - **/ -void -mail_display_redisplay (MailDisplay *mail_display, gboolean unscroll) -{ - redisplay (mail_display, unscroll); } /** @@ -920,7 +902,7 @@ mail_display_set_message (MailDisplay *md, CamelMedium *medium) md->current_message = (CamelMimeMessage*)medium; g_datalist_init (md->data); - redisplay (md, TRUE); + mail_display_redisplay (md, TRUE); if (medium) { camel_object_hook_event (CAMEL_OBJECT (medium), "finalize", clear_data, *(md->data)); diff --git a/mail/mail-display.h b/mail/mail-display.h index c7c45c9bdf..4334d7dfad 100644 --- a/mail/mail-display.h +++ b/mail/mail-display.h @@ -40,6 +40,7 @@ typedef struct { GtkType mail_display_get_type (void); GtkWidget * mail_display_new (void); +void mail_display_queue_redisplay (MailDisplay *mail_display); void mail_display_redisplay (MailDisplay *mail_display, gboolean unscroll); void mail_display_set_message (MailDisplay *mail_display, diff --git a/mail/mail-format.c b/mail/mail-format.c index 610bf27b68..faea36f633 100644 --- a/mail/mail-format.c +++ b/mail/mail-format.c @@ -28,6 +28,7 @@ #include "mail-tools.h" #include "mail-display.h" #include "mail-crypto.h" +#include "mail-mt.h" #include "shell/e-setup.h" #include "e-util/e-html-utils.h" #include @@ -547,7 +548,7 @@ call_handler_function (CamelMimePart *part, MailDisplay *md) if (!handler) { char *id_type; - id_type = mail_identify_mime_part (part); + id_type = mail_identify_mime_part (part, md); if (id_type) { g_free (mime_type); mime_type = id_type; @@ -557,7 +558,8 @@ call_handler_function (CamelMimePart *part, MailDisplay *md) is_inline = mail_part_is_inline (part); attachment_header (part, mime_type, is_inline, md); - if (handler && handler->builtin && is_inline) + if (handler && handler->builtin && is_inline && + mail_content_loaded (wrapper, md)) output = (*handler->builtin) (part, mime_type, md); else output = TRUE; @@ -637,35 +639,118 @@ write_headers (CamelMimeMessage *message, MailDisplay *md) ""); } +struct _load_content_msg { + struct _mail_msg msg; -/* Return the contents of a text-based data wrapper, or NULL if it - * contains only whitespace. + MailDisplay *display; + CamelMimeMessage *message; + CamelDataWrapper *wrapper; +}; + +static char * +load_content_desc (struct _mail_msg *mm, int done) +{ + return g_strdup (_("Loading message content")); +} + +static void +load_content_load (struct _mail_msg *mm) +{ + struct _load_content_msg *m = (struct _load_content_msg *)mm; + CamelStream *memstream; + + memstream = camel_stream_mem_new (); + camel_data_wrapper_write_to_stream (m->wrapper, memstream); + camel_object_unref (CAMEL_OBJECT (memstream)); +} + +static void +load_content_loaded (struct _mail_msg *mm) +{ + struct _load_content_msg *m = (struct _load_content_msg *)mm; + + if (m->display->current_message == m->message) + mail_display_queue_redisplay (m->display); +} + +static void +load_content_free (struct _mail_msg *mm) +{ + struct _load_content_msg *m = (struct _load_content_msg *)mm; + + gtk_object_unref (GTK_OBJECT (m->display)); + camel_object_unref (CAMEL_OBJECT (m->wrapper)); + camel_object_unref (CAMEL_OBJECT (m->message)); +} + +static struct _mail_msg_op load_content_op = { + load_content_desc, + load_content_load, + load_content_loaded, + load_content_free, +}; + +gboolean +mail_content_loaded (CamelDataWrapper *wrapper, MailDisplay *md) +{ + struct _load_content_msg *m; + GHashTable *loading; + + if (!camel_data_wrapper_is_offline (wrapper)) + return TRUE; + + loading = g_datalist_get_data (md->data, "loading"); + if (loading) { + if (g_hash_table_lookup (loading, wrapper)) + return FALSE; + } else { + loading = g_hash_table_new (NULL, NULL); + g_datalist_set_data_full (md->data, "loading", loading, + (GDestroyNotify)g_hash_table_destroy); + } + g_hash_table_insert (loading, wrapper, GINT_TO_POINTER (1)); + + m = mail_msg_new (&load_content_op, NULL, sizeof (*m)); + m->display = md; + gtk_object_ref (GTK_OBJECT (m->display)); + m->message = md->current_message; + camel_object_ref (CAMEL_OBJECT (m->message)); + m->wrapper = wrapper; + camel_object_ref (CAMEL_OBJECT (m->wrapper)); + + e_thread_put (mail_thread_queued, (EMsg *)m); + return FALSE; +} + +/* Return the contents of a data wrapper, or %NULL if it contains only + * whitespace. */ static char * -get_data_wrapper_text (CamelDataWrapper *data) +get_data_wrapper_text (CamelDataWrapper *wrapper) { CamelStream *memstream; GByteArray *ba; char *text, *end; + memstream = camel_stream_mem_new (); ba = g_byte_array_new (); - memstream = camel_stream_mem_new_with_byte_array (ba); - - camel_data_wrapper_write_to_stream (data, memstream); + camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (memstream), ba); + camel_data_wrapper_write_to_stream (wrapper, memstream); + camel_object_unref (CAMEL_OBJECT (memstream)); - for (text = ba->data, end = ba->data + ba->len; text < end; text++) { + for (text = ba->data, end = text + ba->len; text < end; text++) { if (!isspace ((unsigned char)*text)) break; } - if (text < end) { - text = g_malloc (ba->len + 1); - memcpy (text, ba->data, ba->len); - text[ba->len] = '\0'; - } else - text = NULL; + if (text >= end) { + g_byte_array_free (ba, TRUE); + return NULL; + } - camel_object_unref (CAMEL_OBJECT (memstream)); + g_byte_array_append (ba, "", 1); + text = ba->data; + g_byte_array_free (ba, FALSE); return text; } diff --git a/mail/mail-identify.c b/mail/mail-identify.c index 3f86ea361c..61b2d1fe10 100644 --- a/mail/mail-identify.c +++ b/mail/mail-identify.c @@ -35,12 +35,13 @@ /** * mail_identify_mime_part: * @part: a CamelMimePart + * @md: the MailDisplay @part is being shown in * * Try to identify the MIME type of the data in @part (which presumably * doesn't have a useful Content-Type). **/ char * -mail_identify_mime_part (CamelMimePart *part) +mail_identify_mime_part (CamelMimePart *part, MailDisplay *md) { const char *filename, *type; GnomeVFSMimeSniffBuffer *sniffer; @@ -62,17 +63,22 @@ mail_identify_mime_part (CamelMimePart *part) /* Try file magic. */ data = camel_medium_get_content_object (CAMEL_MEDIUM (part)); - ba = g_byte_array_new (); - memstream = camel_stream_mem_new_with_byte_array (ba); - camel_data_wrapper_write_to_stream (data, memstream); - if (ba->len) { - sniffer = gnome_vfs_mime_sniff_buffer_new_from_memory ( - ba->data, ba->len); - type = gnome_vfs_get_mime_type_for_buffer (sniffer); - gnome_vfs_mime_sniff_buffer_free (sniffer); - } else - type = NULL; - camel_object_unref (CAMEL_OBJECT (memstream)); + /* FIXME: In a perfect world, we would not load the content just + * to identify the MIME type. + */ + if (mail_content_loaded (data, md)) { + ba = g_byte_array_new (); + memstream = camel_stream_mem_new_with_byte_array (ba); + camel_data_wrapper_write_to_stream (data, memstream); + if (ba->len) { + sniffer = gnome_vfs_mime_sniff_buffer_new_from_memory ( + ba->data, ba->len); + type = gnome_vfs_get_mime_type_for_buffer (sniffer); + gnome_vfs_mime_sniff_buffer_free (sniffer); + } else + type = NULL; + camel_object_unref (CAMEL_OBJECT (memstream)); + } if (type) return g_strdup (type); diff --git a/mail/mail.h b/mail/mail.h index c80cabfa52..4015fd613a 100644 --- a/mail/mail.h +++ b/mail/mail.h @@ -40,6 +40,7 @@ void mail_format_mime_message (CamelMimeMessage *mime_message, MailDisplay *md); void mail_format_raw_message (CamelMimeMessage *mime_message, MailDisplay *md); +gboolean mail_content_loaded (CamelDataWrapper *wrapper, MailDisplay *display); typedef gboolean (*MailMimeHandlerFn) (CamelMimePart *part, const char *mime_type, @@ -61,7 +62,7 @@ char *mail_get_message_body (CamelDataWrapper *data, gboolean want_plain, gboolean *is_html); /* mail-identify */ -char *mail_identify_mime_part (CamelMimePart *part); +char *mail_identify_mime_part (CamelMimePart *part, MailDisplay *md); /* mail view */ GtkWidget *mail_view_create (CamelFolder *source, const char *uid, CamelMimeMessage *msg); -- cgit v1.2.3