talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit e7e6d98b71b44c060cd0ec5f62fb8db5dd67b83a
parent 550ec19a708181e08e5fe4ae6aad5ffc3a0e2303
Author: Paul <paul@claws-mail.org>
Date:   Mon, 22 Apr 2024 11:54:34 +0100

re-add Colin's attach pasted files commit, with the necessary fix

original commit was 66fccde959a1b4addee971412b35d4b51d8272b1, this includes the patch from Paul Wolneykien (bug 4260) which fixes the bug(s)

Diffstat:
MAUTHORS | 1+
Msrc/compose.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/gtk/authors.h | 1+
3 files changed, 188 insertions(+), 62 deletions(-)

diff --git a/AUTHORS b/AUTHORS @@ -349,3 +349,4 @@ contributors (in addition to the above; based on Changelog) Charles Huber nycex Gianni Ceccarelli + Paul Wolneykien diff --git a/src/compose.c b/src/compose.c @@ -10903,60 +10903,196 @@ static void entry_copy_clipboard(GtkWidget *entry) gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); } +static void paste_text(Compose *compose, GtkWidget *entry, + gboolean wrap, GdkAtom clip, GtkTextIter *insert_place, + const gchar *contents) +{ + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)); + GtkTextMark *mark_start = gtk_text_buffer_get_insert(buffer); + GtkTextIter start_iter, end_iter; + gint start, end; + + if (contents == NULL) + return; + + /* we shouldn't delete the selection when middle-click-pasting, or we + * can't mid-click-paste our own selection */ + if (clip != GDK_SELECTION_PRIMARY) { + undo_paste_clipboard(GTK_TEXT_VIEW(compose->text), compose->undostruct); + gtk_text_buffer_delete_selection(buffer, FALSE, TRUE); + } + + if (insert_place == NULL) { + /* if insert_place isn't specified, insert at the cursor. + * used for Ctrl-V pasting */ + gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark_start); + start = gtk_text_iter_get_offset(&start_iter); + gtk_text_buffer_insert(buffer, &start_iter, contents, strlen(contents)); + } else { + /* if insert_place is specified, paste here. + * used for mid-click-pasting */ + start = gtk_text_iter_get_offset(insert_place); + gtk_text_buffer_insert(buffer, insert_place, contents, strlen(contents)); + if (prefs_common.primary_paste_unselects) + gtk_text_buffer_select_range(buffer, insert_place, insert_place); + } + + if (!wrap) { + /* paste unwrapped: mark the paste so it's not wrapped later */ + end = start + strlen(contents); + gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start); + gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end); + gtk_text_buffer_apply_tag_by_name(buffer, "no_wrap", &start_iter, &end_iter); + } else if (wrap && clip == GDK_SELECTION_PRIMARY) { + /* rewrap paragraph now (after a mid-click-paste) */ + mark_start = gtk_text_buffer_get_insert(buffer); + gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark_start); + gtk_text_iter_backward_char(&start_iter); + compose_beautify_paragraph(compose, &start_iter, TRUE); + } + compose->modified = TRUE; +} + +static void attach_uri_list(Compose *compose, GtkSelectionData *data) +{ + GList *list, *tmp; + int att = 0; + gchar *warn_files = NULL; + + list = uri_list_extract_filenames( + (const gchar *)gtk_selection_data_get_data(data)); + for (tmp = list; tmp != NULL; tmp = tmp->next) { + gchar *utf8_filename = conv_filename_to_utf8((const gchar *)tmp->data); + gchar *tmp_f = g_strdup_printf("%s%s\n", + warn_files?warn_files:"", + utf8_filename); + g_free(warn_files); + warn_files = tmp_f; + att++; + compose_attach_append + (compose, (const gchar *)tmp->data, + utf8_filename, NULL, NULL); + g_free(utf8_filename); + } + if (list) { + compose_changed_cb(NULL, compose); + alertpanel_notice(ngettext( + "The following file has been attached: \n%s", + "The following files have been attached: \n%s", att), warn_files); + g_free(warn_files); + } + list_free_strings_full(list); +} + +int attach_image(Compose *compose, GtkSelectionData *data, const gchar *subtype) +{ + FILE *fp; + const guchar *contents; + gchar *file; + gchar *type; + size_t len; + int r; + + cm_return_val_if_fail(data != NULL, -1); + + contents = gtk_selection_data_get_data(data); + len = gtk_selection_data_get_length(data); + + file = g_strconcat(get_tmp_file(), "-image.", subtype, NULL); + + debug_print("writing image to %s\n", file); + + if ((fp = claws_fopen(file, "wb")) == NULL) { + FILE_OP_ERROR(file, "claws_fopen"); + return -1; + } + + if (claws_fwrite(contents, 1, len, fp) != len) { + FILE_OP_ERROR(file, "claws_fwrite"); + claws_fclose(fp); + claws_unlink(file); + return -1; + } + + r = claws_safe_fclose(fp); + + if (r == EOF) { + FILE_OP_ERROR(file, "claws_fclose"); + claws_unlink(file); + return -1; + } + + type = g_strconcat("image/", subtype, NULL); + + compose_attach_append(compose, (const gchar *)file, + (const gchar *)file, type, NULL); + + alertpanel_notice(_("The pasted image has been attached as: \n%s"), file); + + g_free(file); + g_free(type); + + return 0; +} + static void entry_paste_clipboard(Compose *compose, GtkWidget *entry, - gboolean wrap, GdkAtom clip, GtkTextIter *insert_place) -{ - if (GTK_IS_TEXT_VIEW(entry)) { - GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry)); - GtkTextMark *mark_start = gtk_text_buffer_get_insert(buffer); - GtkTextIter start_iter, end_iter; - gint start, end; - gchar *contents = gtk_clipboard_wait_for_text(gtk_clipboard_get(clip)); - - if (contents == NULL) - return; + gboolean wrap, GdkAtom clip, GtkTextIter *insert_place) +{ + if (GTK_IS_TEXT_VIEW(entry)) { + GdkAtom types = gdk_atom_intern ("TARGETS", FALSE); + GdkAtom *targets = NULL; + int n_targets = 0, i; + gboolean paste_done = FALSE; + GtkClipboard *clipboard = gtk_clipboard_get(clip); + + GtkSelectionData *contents = gtk_clipboard_wait_for_contents( + clipboard, types); + + if (contents != NULL) { + gtk_selection_data_get_targets(contents, &targets, &n_targets); + gtk_selection_data_free(contents); + } + + for (i = 0; i < n_targets; i++) { + GdkAtom atom = targets[i]; + gchar *atom_type = gdk_atom_name(atom); + + if (atom_type != NULL && index(atom_type, '/')) { + GtkSelectionData *data = gtk_clipboard_wait_for_contents( + clipboard, atom); + debug_print("got contents of type %s\n", atom_type); + if (!strcmp(atom_type, "text/plain")) { + /* let the default text handler handle it */ + break; + } else if (!strcmp(atom_type, "text/uri-list")) { + attach_uri_list(compose, data); + + paste_done = TRUE; + break; + } else if (!strncmp(atom_type, "image/", strlen("image/"))) { + gchar *subtype = g_strdup((gchar *)(strstr(atom_type, "/")+1)); + debug_print("image of type %s\n", subtype); + attach_image(compose, data, subtype); + g_free(subtype); - /* we shouldn't delete the selection when middle-click-pasting, or we - * can't mid-click-paste our own selection */ - if (clip != GDK_SELECTION_PRIMARY) { - undo_paste_clipboard(GTK_TEXT_VIEW(compose->text), compose->undostruct); - gtk_text_buffer_delete_selection(buffer, FALSE, TRUE); + paste_done = TRUE; + break; + } + } } - - if (insert_place == NULL) { - /* if insert_place isn't specified, insert at the cursor. - * used for Ctrl-V pasting */ - gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark_start); - start = gtk_text_iter_get_offset(&start_iter); - gtk_text_buffer_insert(buffer, &start_iter, contents, strlen(contents)); - } else { - /* if insert_place is specified, paste here. - * used for mid-click-pasting */ - start = gtk_text_iter_get_offset(insert_place); - gtk_text_buffer_insert(buffer, insert_place, contents, strlen(contents)); - if (prefs_common.primary_paste_unselects) - gtk_text_buffer_select_range(buffer, insert_place, insert_place); - } - - if (!wrap) { - /* paste unwrapped: mark the paste so it's not wrapped later */ - end = start + strlen(contents); - gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start); - gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end); - gtk_text_buffer_apply_tag_by_name(buffer, "no_wrap", &start_iter, &end_iter); - } else if (wrap && clip == GDK_SELECTION_PRIMARY) { - /* rewrap paragraph now (after a mid-click-paste) */ - mark_start = gtk_text_buffer_get_insert(buffer); - gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark_start); - gtk_text_iter_backward_char(&start_iter); - compose_beautify_paragraph(compose, &start_iter, TRUE); - } - } else if (GTK_IS_EDITABLE(entry)) + if (!paste_done) { + gchar *def_text = gtk_clipboard_wait_for_text(clipboard); + paste_text(compose, entry, wrap, clip, + insert_place, def_text); + g_free(def_text); + } + g_free(targets); + } else if (GTK_IS_EDITABLE(entry)) { gtk_editable_paste_clipboard (GTK_EDITABLE(entry)); - - compose->modified = TRUE; + compose->modified = TRUE; + } } - + static void entry_allsel(GtkWidget *entry) { if (GTK_IS_EDITABLE(entry)) @@ -11616,25 +11752,13 @@ static void compose_attach_drag_received_cb (GtkWidget *widget, gpointer user_data) { Compose *compose = (Compose *)user_data; - GList *list, *tmp; GdkAtom type; type = gtk_selection_data_get_data_type(data); if ((gdk_atom_name(type) && !strcmp(gdk_atom_name(type), "text/uri-list")) && gtk_drag_get_source_widget(context) != summary_get_main_widget(mainwindow_get_mainwindow()->summaryview)) { - list = uri_list_extract_filenames( - (const gchar *)gtk_selection_data_get_data(data)); - for (tmp = list; tmp != NULL; tmp = tmp->next) { - gchar *utf8_filename = conv_filename_to_utf8((const gchar *)tmp->data); - compose_attach_append - (compose, (const gchar *)tmp->data, - utf8_filename, NULL, NULL); - g_free(utf8_filename); - } - if (list) - compose_changed_cb(NULL, compose); - list_free_strings_full(list); + attach_uri_list(compose, data); } else if (gtk_drag_get_source_widget(context) == summary_get_main_widget(mainwindow_get_mainwindow()->summaryview)) { /* comes from our summaryview */ diff --git a/src/gtk/authors.h b/src/gtk/authors.h @@ -333,6 +333,7 @@ static char *CONTRIBS_LIST[] = { "Rafal Weglarz", "Florian Weimer", "Martin Wicke", +"Paul Wolneykien", "Bob Woodside", "YAMAGUCHI", "T. Yamamoto",