changeset 8698:f36eee61c85f

[gaim-migrate @ 9451] "This patch hopefully fixes bugs 31, 32, 33, and 39 It also does the thing Sean /ms'd me to do with <hr> tags. At least I hope this is right." --Tim Ringenbach 31: Cutting text from the IM HTML cuts only text without any markup or smileys. 32: Pasting text closes formatting tags before inserting text. 33: Pasting plain text removes all line breaks. 39: Copying rich text and pasting into locations that don't support this, will still paste the HTML and try to send it on to its destination. Luke pointed out that copy/pasting in IRC will do this. committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Sun, 18 Apr 2004 13:01:44 +0000
parents 725413cc9fb9
children 775bd10da7f2
files src/gtkimhtml.c
diffstat 1 files changed, 95 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/gtkimhtml.c	Sun Apr 18 06:22:42 2004 +0000
+++ b/src/gtkimhtml.c	Sun Apr 18 13:01:44 2004 +0000
@@ -69,7 +69,7 @@
 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length);
-void gtk_imhtml_close_tags(GtkIMHtml *imhtml);
+void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter);
 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml);
 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml);
 
@@ -630,12 +630,60 @@
 	g_signal_stop_emission_by_name(imhtml, "copy-clipboard");
 }
 
+static void cut_clipboard_cb(GtkIMHtml *imhtml, gpointer unused)
+{
+	GtkTextIter start, end;
+	GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer);
+	GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
+
+	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel);
+	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins);
+
+	gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
+				     selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
+				     (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
+				     (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
+
+	if (imhtml->clipboard_html_string) {
+		g_free(imhtml->clipboard_html_string);
+		g_free(imhtml->clipboard_text_string);
+	}
+
+	imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end);
+	imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end);
+
+#ifdef _WIN32
+	/* We're going to still copy plain text, but let's toss the "HTML Format"
+	   we need into the windows clipboard now as well.	*/
+	HGLOBAL hdata;
+	gchar *clipboard = clipboard_html_to_win32(imhtml->clipboard_html_string);
+	gchar *buffer;
+	gint length = strlen(clipboard);
+	if(clipboard != NULL) {
+		OpenClipboard(NULL);
+		hdata = GlobalAlloc(GMEM_MOVEABLE, length);
+		buffer = GlobalLock(hdata);
+        memcpy(buffer, clipboard, length);
+		GlobalUnlock(hdata);
+        SetClipboardData(win_html_fmt, hdata);
+		CloseClipboard();
+		g_free(clipboard);
+	}
+#endif
+
+	if (imhtml->editable)
+		gtk_text_buffer_delete_selection(imhtml->text_buffer, FALSE, FALSE);
+	g_signal_stop_emission_by_name(imhtml, "cut-clipboard");
+}
+
 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data)
 {
 	char *text;
 	guint16 c;
 	GtkIMHtml *imhtml = data;
 	GtkTextIter iter;
+	GtkIMHtmlOptions flags = GTK_IMHTML_NO_NEWLINE;
+	gboolean plaintext = FALSE;
 
 	if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml)))
 		return;
@@ -668,11 +716,17 @@
 	} else
 #endif
 	if (selection_data->length < 0) {
+		char *tmp;
 		text = gtk_clipboard_wait_for_text(clipboard);
+		flags = 0;
+		plaintext = TRUE;
 
 		if (text == NULL)
 			return;
 
+		tmp = gaim_escape_html(text);
+		g_free(text);
+		text = tmp;
 	} else {
 		text = g_malloc((selection_data->format / 8) * selection_data->length);
 		memcpy(text, selection_data->data, selection_data->length * (selection_data->format / 8));
@@ -684,12 +738,25 @@
 		char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL);
 		g_free(text);
 		text = utf8;
+		if (!text) {
+			gaim_debug_warning("gtkimhtml", "g_convert failed in paste_received_cb\n");
+			return;
+		}
 	}
-	if (!imhtml->wbfo)
-		gtk_imhtml_close_tags(imhtml);
+
+	if (!(*text) || !g_utf8_validate(text, -1, NULL)) {
+		gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in paste_received_cb\n");
+		g_free(text);
+		return;
+	}
+
 	gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer));
-	gtk_imhtml_insert_html_at_iter(imhtml, text, GTK_IMHTML_NO_NEWLINE, &iter);
+	if (!imhtml->wbfo && !plaintext)
+		gtk_imhtml_close_tags(imhtml, &iter);
+	gtk_imhtml_insert_html_at_iter(imhtml, text, flags, &iter);
 	gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter);
+	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), gtk_text_buffer_get_insert(imhtml->text_buffer),
+	                             0, FALSE, 0.0, 0.0);
 	g_free(text);
 }
 
@@ -892,6 +959,7 @@
 
 #if GTK_CHECK_VERSION(2,2,0)
 	g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL);
+	g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL);
 	g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL);
 	//g_signal_connect_after(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml);
 	g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL);
@@ -1850,15 +1918,15 @@
 						ws[0] = '\0'; wpos = 0;
 						/* NEW_BIT (NEW_TEXT_BIT); */
 
-						if (font->face) {
+						if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) {
 							gtk_imhtml_toggle_fontface(imhtml, NULL);
 							g_free (font->face);
 						}
-						if (font->fore) {
+						if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) {
 							gtk_imhtml_toggle_forecolor(imhtml, NULL);
 							g_free (font->fore);
 						}
-						if (font->back) {
+						if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) {
 							gtk_imhtml_toggle_backcolor(imhtml, NULL);
 							g_free (font->back);
 						}
@@ -1866,20 +1934,20 @@
 							g_free (font->sml);
 						g_free (font);
 
-						if (font->size != 3)
+						if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)))
 							gtk_imhtml_font_set_size(imhtml, 3);
 
 						fonts = fonts->next;
 						if (fonts) {
 							GtkIMHtmlFontDetail *font = fonts->data;
 
-							if (font->face)
+							if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE))
 								gtk_imhtml_toggle_fontface(imhtml, font->face);
-							if (font->fore)
+							if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR))
 								gtk_imhtml_toggle_forecolor(imhtml, font->fore);
-							if (font->back)
+							if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR))
 								gtk_imhtml_toggle_backcolor(imhtml, font->back);
-							if (font->size != 3)
+							if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)))
 								gtk_imhtml_font_set_size(imhtml, font->size);
 						}
 					}
@@ -1965,7 +2033,8 @@
 							font->size = oldfont->size;
 						else
 							font->size = 3;
-						gtk_imhtml_font_set_size(imhtml, font->size);
+						if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)))
+							gtk_imhtml_font_set_size(imhtml, font->size);
 						g_free(size);
 						fonts = g_slist_prepend (fonts, font);
 					}
@@ -2317,7 +2386,7 @@
 		g_free(bg);
 
 	if (!imhtml->wbfo)
-		gtk_imhtml_close_tags(imhtml);
+		gtk_imhtml_close_tags(imhtml, iter);
 
 	object = g_object_ref(G_OBJECT(imhtml));
 	g_signal_emit(object, signals[UPDATE_FORMAT], 0);
@@ -2656,7 +2725,8 @@
 {
 	GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale;
 	GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
-	g_object_set_data(G_OBJECT(anchor), "text_tag", "<hr>");
+	g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>");
+	g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n");
 	gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor);
 }
 
@@ -3334,7 +3404,8 @@
 	}
 
 	anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
-	g_object_set_data(G_OBJECT(anchor), "text_tag", unescaped);
+	g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", unescaped, g_free);
+	g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free);
 
 	annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped);
 	if(annipixbuf) {
@@ -3478,8 +3549,11 @@
 
 		if (c == 0xFFFC) {
 			GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter);
-			char *text = g_object_get_data(G_OBJECT(anchor), "text_tag");
-			str = g_string_append(str, text);
+			char *text = NULL;
+			if (anchor)
+				text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext");
+			if (text)
+				str = g_string_append(str, text);
 		} else 	if (c == '<') {
 			str = g_string_append(str, "&lt;");
 		} else if (c == '>') {
@@ -3535,10 +3609,8 @@
 	return g_string_free(str, FALSE);
 }
 
-void gtk_imhtml_close_tags(GtkIMHtml *imhtml)
+void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter)
 {
-	GtkTextIter iter;
-
 	if (imhtml->edit.bold)
 		gtk_imhtml_toggle_bold(imhtml);
 
@@ -3559,8 +3631,7 @@
 
 	imhtml->edit.fontsize = 0;
 
-	gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter);
-	gtk_text_buffer_remove_all_tags(imhtml->text_buffer, &iter, &iter);
+	gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter);
 
 }
 
@@ -3622,7 +3693,7 @@
 
 			anchor = gtk_text_iter_get_child_anchor(&iter);
 			if (anchor)
-				text = g_object_get_data(G_OBJECT(anchor), "text_tag");
+				text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext");
 			if (text)
 				str = g_string_append(str, text);
 		} else {