Compose: handle pasted images and text/uri-list (files) and attach them

This commit is contained in:
Colin Leroy 2019-07-07 10:43:45 +02:00 committed by Andrej Kacian
parent 3e3fa274fd
commit 95bd2a18ed

View file

@ -10897,58 +10897,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));
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);
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);
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);
}
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);
for (i = 0; i < n_targets; i++) {
GdkAtom atom = targets[i];
gchar *atom_type = gdk_atom_name(atom);
if (atom_type != NULL) {
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);
paste_done = TRUE;
break;
}
}
}
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);
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);
}
} else if (GTK_IS_EDITABLE(entry))
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)
@ -11608,25 +11746,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 */