#include "image_viewer.h"
#include "filesel.h"
#include "base64.h"
+#include "inputdialog.h"
+#include "timing.h"
struct _ClickableText
{
GtkTextIter *iter,
TextView *textview);
-static void textview_smooth_scroll_do (TextView *textview,
- gfloat old_value,
- gfloat last_value,
- gint step);
-static void textview_smooth_scroll_one_line (TextView *textview,
- gboolean up);
-static gboolean textview_smooth_scroll_page (TextView *textview,
- gboolean up);
-
static gboolean textview_uri_security_check (TextView *textview,
ClickableText *uri);
static void textview_uri_list_remove_all (GSList *uri_list);
void textview_show_message(TextView *textview, MimeInfo *mimeinfo,
const gchar *file)
{
+ textview->loading = TRUE;
+ textview->stop_loading = FALSE;
+
textview_clear(textview);
textview_add_parts(textview, mimeinfo);
textview_set_position(textview, 0);
+
+ textview->loading = FALSE;
+ textview->stop_loading = FALSE;
}
void textview_show_part(TextView *textview, MimeInfo *mimeinfo, FILE *fp)
{
+ START_TIMING("textview_show_part");
g_return_if_fail(mimeinfo != NULL);
g_return_if_fail(fp != NULL);
if ((mimeinfo->type == MIMETYPE_MULTIPART) ||
((mimeinfo->type == MIMETYPE_MESSAGE) && !g_ascii_strcasecmp(mimeinfo->subtype, "rfc822"))) {
+ textview->loading = TRUE;
+ textview->stop_loading = FALSE;
+
textview_clear(textview);
textview_add_parts(textview, mimeinfo);
+
+ textview->loading = FALSE;
+ textview->stop_loading = FALSE;
+ END_TIMING();
return;
}
+ textview->loading = TRUE;
+ textview->stop_loading = FALSE;
if (fseek(fp, mimeinfo->offset, SEEK_SET) < 0)
perror("fseek");
textview_add_parts(textview, mimeinfo);
else
textview_write_body(textview, mimeinfo);
+
+ textview->loading = FALSE;
+ textview->stop_loading = FALSE;
+ END_TIMING();
}
#define TEXT_INSERT(str) \
const gchar *name;
gchar *content_type;
gint charcount;
+ START_TIMING("textview_add_part");
g_return_if_fail(mimeinfo != NULL);
text = GTK_TEXT_VIEW(textview->text);
charcount = gtk_text_buffer_get_char_count(buffer);
gtk_text_buffer_get_end_iter(buffer, &iter);
- if (mimeinfo->type == MIMETYPE_MULTIPART) return;
+ if (textview->stop_loading) {
+ return;
+ }
+ if (mimeinfo->type == MIMETYPE_MULTIPART) {
+ END_TIMING();
+ return;
+ }
if ((mimeinfo->type == MIMETYPE_MESSAGE) && !g_ascii_strcasecmp(mimeinfo->subtype, "rfc822")) {
FILE *fp;
procheader_header_array_destroy(headers);
}
fclose(fp);
+ END_TIMING();
return;
}
gchar *filename;
ClickableText *uri;
gchar *uri_str;
+ START_TIMING("inserting image");
filename = procmime_get_tmp_file_name(mimeinfo);
+
if (procmime_get_part(filename, mimeinfo) < 0) {
g_warning("Can't get the image file.");
g_free(filename);
+ END_TIMING();
return;
}
- pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+ if (!prefs_common.resize_img) {
+ pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+ } else {
+ gint w, h;
+ gdk_pixbuf_get_file_info(filename, &w, &h);
+ if (w > textview->scrolledwin->allocation.width - 100)
+ pixbuf = gdk_pixbuf_new_from_file_at_scale(filename,
+ textview->scrolledwin->allocation.width - 100,
+ -1, TRUE, &error);
+ else
+ pixbuf = gdk_pixbuf_new_from_file(filename, &error);
+ }
if (error != NULL) {
g_warning("%s\n", error->message);
g_error_free(error);
if (!pixbuf) {
g_warning("Can't load the image.");
g_free(filename);
+ END_TIMING();
return;
}
- if (prefs_common.resize_img) {
- int new_width, new_height;
- GdkPixbuf *scaled;
- image_viewer_get_resized_size(gdk_pixbuf_get_width(pixbuf),
- gdk_pixbuf_get_height(pixbuf),
- textview->scrolledwin->allocation.width - 100,
- gdk_pixbuf_get_height(pixbuf),
- &new_width, &new_height);
- scaled = gdk_pixbuf_scale_simple
- (pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
-
- g_object_unref(pixbuf);
- pixbuf = scaled;
- }
-
uri_str = g_filename_to_uri(filename, NULL, NULL);
if (uri_str) {
uri = g_new0(ClickableText, 1);
g_object_unref(pixbuf);
g_free(filename);
+ END_TIMING();
+ GTK_EVENTS_FLUSH();
}
} else if (mimeinfo->type == MIMETYPE_TEXT) {
if (prefs_common.display_header && (charcount > 0))
textview_write_body(textview, mimeinfo);
}
+ END_TIMING();
}
static void recursive_add_parts(TextView *textview, GNode *node)
{
GNode * iter;
MimeInfo *mimeinfo;
-
+ START_TIMING("recursive_add_parts");
+
mimeinfo = (MimeInfo *) node->data;
textview_add_part(textview, mimeinfo);
if ((mimeinfo->type != MIMETYPE_MULTIPART) &&
- (mimeinfo->type != MIMETYPE_MESSAGE))
+ (mimeinfo->type != MIMETYPE_MESSAGE)) {
+ END_TIMING();
return;
-
+ }
if (g_ascii_strcasecmp(mimeinfo->subtype, "alternative") == 0) {
GNode * prefered_body;
int prefered_score;
recursive_add_parts(textview, iter);
}
}
+ END_TIMING();
}
static void textview_add_parts(TextView *textview, MimeInfo *mimeinfo)
CodeConverter *conv;
const gchar *charset, *p, *cmd;
GSList *cur;
+ int lines = 0;
if (textview->messageview->forced_charset)
charset = textview->messageview->forced_charset;
}
close(pfd[1]);
tmpfp = fdopen(pfd[0], "rb");
- while (fgets(buf, sizeof(buf), tmpfp))
+ while (fgets(buf, sizeof(buf), tmpfp)) {
textview_write_line(textview, buf, conv);
+
+ lines++;
+ if (lines % 500 == 0)
+ GTK_EVENTS_FLUSH();
+ if (textview->stop_loading) {
+ fclose(tmpfp);
+ waitpid(pid, pfd, 0);
+ unlink(fname);
+ return;
+ }
+ }
+
fclose(tmpfp);
waitpid(pid, pfd, 0);
unlink(fname);
} else {
textview_default:
+ lines = 0;
tmpfp = g_fopen(mimeinfo->data.filename, "rb");
fseek(tmpfp, mimeinfo->offset, SEEK_SET);
debug_print("Viewing text content of type: %s (length: %d)\n", mimeinfo->subtype, mimeinfo->length);
- while ((fgets(buf, sizeof(buf), tmpfp) != NULL) &&
- (ftell(tmpfp) <= mimeinfo->offset + mimeinfo->length))
+ while ((ftell(tmpfp) < mimeinfo->offset + mimeinfo->length) &&
+ (fgets(buf, sizeof(buf), tmpfp) != NULL)) {
textview_write_line(textview, buf, conv);
+ lines++;
+ if (lines % 500 == 0)
+ GTK_EVENTS_FLUSH();
+ if (textview->stop_loading) {
+ fclose(tmpfp);
+ return;
+ }
+ }
fclose(tmpfp);
}
conv_code_converter_destroy(conv);
procmime_force_encoding(0);
+ lines = 0;
for (cur = textview->uri_list; cur; cur = cur->next) {
ClickableText *uri = (ClickableText *)cur->data;
if (!uri->is_quote)
if (!prefs_common.hide_quotes ||
uri->quote_level+1 < prefs_common.hide_quotes) {
textview_toggle_quote(textview, uri, TRUE);
+ lines++;
+ if (lines % 500 == 0)
+ GTK_EVENTS_FLUSH();
+ if (textview->stop_loading) {
+ return;
+ }
}
}
}
{
SC_HTMLParser *parser;
gchar *str;
+ gint lines = 0;
parser = sc_html_parser_new(fp, conv);
g_return_if_fail(parser != NULL);
textview_write_link(textview, str, parser->href, NULL);
} else
textview_write_line(textview, str, NULL);
+ lines++;
+ if (lines % 500 == 0)
+ GTK_EVENTS_FLUSH();
+ if (textview->stop_loading) {
+ return;
+ }
}
textview_write_line(textview, "\n", NULL);
sc_html_parser_destroy(parser);
{
ERTFParser *parser;
gchar *str;
+ gint lines = 0;
parser = ertf_parser_new(fp, conv);
g_return_if_fail(parser != NULL);
while ((str = ertf_parse(parser)) != NULL) {
textview_write_line(textview, str, NULL);
+ lines++;
+ if (lines % 500 == 0)
+ GTK_EVENTS_FLUSH();
+ if (textview->stop_loading) {
+ return;
+ }
}
ertf_parser_destroy(parser);
/* colorize this line */
if (head.next) {
- const gchar *normal_text = mybuf;
-
/* insert URIs */
- for (last = head.next; last != NULL;
- normal_text = last->ep, last = last->next) {
+ for (last = head.next; last != NULL; last = last->next) {
ClickableText *uri;
+ gint start_offset, end_offset;
+ gchar *tmp_str;
+ gchar old_char;
uri = g_new0(ClickableText, 1);
uri->uri = parser[last->pti].build_uri(last->bp,
last->ep);
-
- gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, last->bp - mybuf + offset);
- gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, last->ep - mybuf + offset);
+
+ tmp_str = mybuf;
+ old_char = tmp_str[last->ep - mybuf];
+ tmp_str[last->ep - mybuf] = '\0';
+ end_offset = g_utf8_strlen(tmp_str, -1);
+ tmp_str[last->ep - mybuf] = old_char;
+
+ old_char = tmp_str[last->bp - mybuf];
+ tmp_str[last->bp - mybuf] = '\0';
+ start_offset = g_utf8_strlen(tmp_str, -1);
+ tmp_str[last->bp - mybuf] = old_char;
+
+ gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start_offset + offset);
+ gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end_offset + offset);
uri->start = gtk_text_iter_get_offset(&start_iter);
GtkTextIter iter;
gchar buf[BUFFSIZE];
gchar *fg_color;
- gint quotelevel = -1;
+ gint quotelevel = -1, real_quotelevel = -1;
gchar quote_tag_str[10];
text = GTK_TEXT_VIEW(textview->text);
level is colored using a different color. */
if (prefs_common.enable_color
&& line_has_quote_char(buf, prefs_common.quote_chars)) {
- quotelevel = get_quote_level(buf, prefs_common.quote_chars);
-
+ real_quotelevel = get_quote_level(buf, prefs_common.quote_chars);
+ quotelevel = real_quotelevel;
/* set up the correct foreground color */
if (quotelevel > 2) {
/* recycle colors */
textview->is_in_signature = TRUE;
}
- if (quotelevel > -1) {
- if ( previousquotelevel != quotelevel ) {
+ if (real_quotelevel > -1) {
+ if ( previousquotelevel != real_quotelevel ) {
ClickableText *uri;
uri = g_new0(ClickableText, 1);
uri->uri = g_strdup("");
uri->filename = NULL;
uri->fg_color = g_strdup(fg_color);
uri->is_quote = TRUE;
- uri->quote_level = quotelevel;
+ uri->quote_level = real_quotelevel;
textview->uri_list =
g_slist_append(textview->uri_list, uri);
gtk_text_buffer_insert(buffer, &iter, " \n", -1);
- previousquotelevel = quotelevel;
+ previousquotelevel = real_quotelevel;
} else {
GSList *last = g_slist_last(textview->uri_list);
ClickableText *lasturi = (ClickableText *)last->data;
|| !prefs_common.display_xface)
goto bail;
- if (!msginfo->face) {
+ if (!msginfo->extradata || !msginfo->extradata->face) {
goto bail;
}
if (textview->image)
gtk_widget_destroy(textview->image);
- textview->image = face_get_from_header(msginfo->face);
+ textview->image = face_get_from_header(msginfo->extradata->face);
g_return_if_fail(textview->image != NULL);
gtk_widget_show(textview->image);
|| !prefs_common.display_xface)
goto bail;
- if (!msginfo)
+ if (!msginfo || !msginfo->extradata)
goto bail;
- if (msginfo->face)
+ if (msginfo->extradata->face)
return;
- if (!msginfo->xface || strlen(msginfo->xface) < 5) {
+ if (!msginfo->extradata->xface || strlen(msginfo->extradata->xface) < 5) {
goto bail;
}
if (textview->image)
gtk_widget_destroy(textview->image);
- textview->image = xface_get_from_header(msginfo->xface,
+ textview->image = xface_get_from_header(msginfo->extradata->xface,
&textview->text->style->white,
textview->text->window);
g_return_if_fail(textview->image != NULL);
{
GtkTextView *text = GTK_TEXT_VIEW(textview->text);
GtkAdjustment *vadj = text->vadjustment;
- gfloat upper;
- if (prefs_common.enable_smooth_scroll) {
- textview_smooth_scroll_one_line(textview, up);
- return;
- }
-
- if (!up) {
- upper = vadj->upper - vadj->page_size;
- if (vadj->value < upper) {
- vadj->value += vadj->step_increment;
- vadj->value = MIN(vadj->value, upper);
- g_signal_emit_by_name(G_OBJECT(vadj),
- "value_changed", 0);
- }
- } else {
- if (vadj->value > 0.0) {
- vadj->value -= vadj->step_increment;
- vadj->value = MAX(vadj->value, 0.0);
- g_signal_emit_by_name(G_OBJECT(vadj),
- "value_changed", 0);
- }
- }
+ gtkutils_scroll_one_line(GTK_WIDGET(text), vadj, up);
}
gboolean textview_scroll_page(TextView *textview, gboolean up)
{
GtkTextView *text = GTK_TEXT_VIEW(textview->text);
GtkAdjustment *vadj = text->vadjustment;
- gfloat upper;
- gfloat page_incr;
-
- if (prefs_common.enable_smooth_scroll)
- return textview_smooth_scroll_page(textview, up);
-
- if (prefs_common.scroll_halfpage)
- page_incr = vadj->page_increment / 2;
- else
- page_incr = vadj->page_increment;
-
- if (!up) {
- upper = vadj->upper - vadj->page_size;
- if (vadj->value < upper) {
- vadj->value += page_incr;
- vadj->value = MIN(vadj->value, upper);
- g_signal_emit_by_name(G_OBJECT(vadj),
- "value_changed", 0);
- } else
- return FALSE;
- } else {
- if (vadj->value > 0.0) {
- vadj->value -= page_incr;
- vadj->value = MAX(vadj->value, 0.0);
- g_signal_emit_by_name(G_OBJECT(vadj),
- "value_changed", 0);
- } else
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void textview_smooth_scroll_do(TextView *textview,
- gfloat old_value, gfloat last_value,
- gint step)
-{
- GtkTextView *text = GTK_TEXT_VIEW(textview->text);
- GtkAdjustment *vadj = text->vadjustment;
- gint change_value;
- gboolean up;
- gint i;
-
- if (old_value < last_value) {
- change_value = last_value - old_value;
- up = FALSE;
- } else {
- change_value = old_value - last_value;
- up = TRUE;
- }
-
- for (i = step; i <= change_value; i += step) {
- vadj->value = old_value + (up ? -i : i);
- g_signal_emit_by_name(G_OBJECT(vadj),
- "value_changed", 0);
- }
-
- vadj->value = last_value;
- g_signal_emit_by_name(G_OBJECT(vadj), "value_changed", 0);
-
- gtk_widget_queue_draw(GTK_WIDGET(text));
-}
-
-static void textview_smooth_scroll_one_line(TextView *textview, gboolean up)
-{
- GtkTextView *text = GTK_TEXT_VIEW(textview->text);
- GtkAdjustment *vadj = text->vadjustment;
- gfloat upper;
- gfloat old_value;
- gfloat last_value;
-
- if (!up) {
- upper = vadj->upper - vadj->page_size;
- if (vadj->value < upper) {
- old_value = vadj->value;
- last_value = vadj->value + vadj->step_increment;
- last_value = MIN(last_value, upper);
-
- textview_smooth_scroll_do(textview, old_value,
- last_value,
- prefs_common.scroll_step);
- }
- } else {
- if (vadj->value > 0.0) {
- old_value = vadj->value;
- last_value = vadj->value - vadj->step_increment;
- last_value = MAX(last_value, 0.0);
-
- textview_smooth_scroll_do(textview, old_value,
- last_value,
- prefs_common.scroll_step);
- }
- }
-}
-
-static gboolean textview_smooth_scroll_page(TextView *textview, gboolean up)
-{
- GtkTextView *text = GTK_TEXT_VIEW(textview->text);
- GtkAdjustment *vadj = text->vadjustment;
- gfloat upper;
- gfloat page_incr;
- gfloat old_value;
- gfloat last_value;
-
- if (prefs_common.scroll_halfpage)
- page_incr = vadj->page_increment / 2;
- else
- page_incr = vadj->page_increment;
-
- if (!up) {
- upper = vadj->upper - vadj->page_size;
- if (vadj->value < upper) {
- old_value = vadj->value;
- last_value = vadj->value + page_incr;
- last_value = MIN(last_value, upper);
-
- textview_smooth_scroll_do(textview, old_value,
- last_value,
- prefs_common.scroll_step);
- } else
- return FALSE;
- } else {
- if (vadj->value > 0.0) {
- old_value = vadj->value;
- last_value = vadj->value - page_incr;
- last_value = MAX(last_value, 0.0);
-
- textview_smooth_scroll_do(textview, old_value,
- last_value,
- prefs_common.scroll_step);
- } else
- return FALSE;
- }
- return TRUE;
+ return gtkutils_scroll_page(GTK_WIDGET(text), vadj, up);
}
#define KEY_PRESS_EVENT_STOP() \
if (summaryview)
summary_pass_key_press_event(summaryview, event);
else
- textview_scroll_page
- (textview,
+ mimeview_scroll_page
+ (messageview->mimeview,
(event->state &
(GDK_SHIFT_MASK|GDK_MOD1_MASK)) != 0);
break;
case GDK_BackSpace:
- textview_scroll_page(textview, TRUE);
+ mimeview_scroll_page(messageview->mimeview, TRUE);
break;
case GDK_Return:
- textview_scroll_one_line
- (textview, (event->state &
+ mimeview_scroll_one_line
+ (messageview->mimeview, (event->state &
(GDK_SHIFT_MASK|GDK_MOD1_MASK)) != 0);
break;
case GDK_Delete:
GdkEventMotion *event,
TextView *textview)
{
+ if (textview->loading)
+ return FALSE;
textview_uri_update(textview, event->x, event->y);
gdk_window_get_pointer(widget->window, NULL, NULL, NULL);
GdkEventCrossing *event,
TextView *textview)
{
+ if (textview->loading)
+ return FALSE;
textview_uri_update(textview, -1, -1);
return FALSE;
gint wx, wy;
GdkWindow *window;
+ if (textview->loading)
+ return FALSE;
+
window = gtk_text_view_get_window(GTK_TEXT_VIEW(widget),
GTK_TEXT_WINDOW_TEXT);
GtkTextIter iter;
GSList *tags;
GSList *cur;
-
+
gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(textview->text),
GTK_TEXT_WINDOW_WIDGET,
x, y, &bx, &by);
g_object_get(G_OBJECT(tag), "name", &name, NULL);
- if ((!strcmp(name, "link") || !strcmp(name, "qlink"))
+ if ((!strcmp(name, "link"))
&& textview_get_uri_range(textview, &iter, tag,
&start_iter, &end_iter)) {
&iter, tag,
&start_iter,
&end_iter);
- }
+ }
g_free(name);
-
if (uri)
break;
}
end_pos == uri_->end) {
uri = uri_;
break;
- } else if (start_pos == uri_->start ||
+ }
+ }
+ for (cur = textview->uri_list; uri == NULL && cur != NULL; cur = cur->next) {
+ ClickableText *uri_ = (ClickableText *)cur->data;
+ if (start_pos == uri_->start ||
end_pos == uri_->end) {
/* in case of contiguous links, textview_get_uri_range
* returns a broader range (start of 1st link to end
bevent = (GdkEventButton *) event;
/* doubleclick: open compose / add address / browser */
- if ((event->type == (qlink ? GDK_2BUTTON_PRESS:GDK_BUTTON_PRESS) && bevent->button == 1) ||
+ if (qlink && event->type == GDK_BUTTON_PRESS && bevent->button != 1) {
+ /* pass rightclick through */
+ return FALSE;
+ } else if ((event->type == (qlink ? GDK_2BUTTON_PRESS:GDK_BUTTON_PRESS) && bevent->button == 1) ||
bevent->button == 2 || bevent->button == 3) {
if (uri->filename && !g_ascii_strncasecmp(uri->filename, "sc://", 5)) {
MimeView *mimeview =
} else if (qlink && bevent->button == 1) {
textview_toggle_quote(textview, uri, FALSE);
return TRUE;
-
} else if (!g_ascii_strncasecmp(uri->uri, "mailto:", 7)) {
if (bevent->button == 3) {
g_object_set_data(
ClickableText *uri = g_object_get_data(G_OBJECT(textview->file_popup_menu),
"menu_button");
- static gchar *default_cmdline = DEFAULT_IMAGE_VIEWER_CMD;
+ gchar *cmd = NULL;
gchar buf[1024];
- const gchar *cmd;
- const gchar *def_cmd;
const gchar *p;
gchar *filename = NULL;
gchar *tmp_filename = NULL;
copy_file(tmp_filename, filename, FALSE);
g_free(tmp_filename);
- cmd = prefs_common.mime_image_viewer;
- def_cmd = default_cmdline;
-
+ cmd = mailcap_get_command_for_type("image/jpeg", filename);
+ if (cmd == NULL) {
+ gboolean remember = FALSE;
+ cmd = input_dialog_combo_remember
+ (_("Open with"),
+ _("Enter the command line to open file:\n"
+ "('%s' will be replaced with file name)"),
+ prefs_common.mime_open_cmd,
+ prefs_common.mime_open_cmd_history,
+ TRUE, &remember);
+ if (cmd && remember) {
+ mailcap_update_default("image/jpeg", cmd);
+ }
+ }
if (cmd && (p = strchr(cmd, '%')) && *(p + 1) == 's' &&
!strchr(p + 2, '%'))
g_snprintf(buf, sizeof(buf), cmd, filename);
else {
- if (cmd)
- g_warning("Image viewer command line is invalid: '%s'", cmd);
- if (def_cmd)
- g_snprintf(buf, sizeof(buf), def_cmd, filename);
- else
- return;
+ g_warning("Image viewer command line is invalid: '%s'", cmd);
+ return;
}
execute_command_line(buf, TRUE);
g_free(filename);
+ g_free(cmd);
g_object_set_data(G_OBJECT(textview->file_popup_menu), "menu_button",
NULL);