comparison src/gtkimhtml.c @ 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 f83de0baf171
children 4c7bc4b0f190
comparison
equal deleted inserted replaced
8697:725413cc9fb9 8698:f36eee61c85f
67 #define TOOLTIP_TIMEOUT 500 67 #define TOOLTIP_TIMEOUT 500
68 68
69 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); 69 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
70 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); 70 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
71 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); 71 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length);
72 void gtk_imhtml_close_tags(GtkIMHtml *imhtml); 72 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter);
73 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); 73 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml);
74 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml); 74 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml);
75 75
76 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a 76 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a
77 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ 77 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */
628 #endif 628 #endif
629 629
630 g_signal_stop_emission_by_name(imhtml, "copy-clipboard"); 630 g_signal_stop_emission_by_name(imhtml, "copy-clipboard");
631 } 631 }
632 632
633 static void cut_clipboard_cb(GtkIMHtml *imhtml, gpointer unused)
634 {
635 GtkTextIter start, end;
636 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer);
637 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
638
639 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel);
640 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins);
641
642 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
643 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
644 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
645 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
646
647 if (imhtml->clipboard_html_string) {
648 g_free(imhtml->clipboard_html_string);
649 g_free(imhtml->clipboard_text_string);
650 }
651
652 imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end);
653 imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end);
654
655 #ifdef _WIN32
656 /* We're going to still copy plain text, but let's toss the "HTML Format"
657 we need into the windows clipboard now as well. */
658 HGLOBAL hdata;
659 gchar *clipboard = clipboard_html_to_win32(imhtml->clipboard_html_string);
660 gchar *buffer;
661 gint length = strlen(clipboard);
662 if(clipboard != NULL) {
663 OpenClipboard(NULL);
664 hdata = GlobalAlloc(GMEM_MOVEABLE, length);
665 buffer = GlobalLock(hdata);
666 memcpy(buffer, clipboard, length);
667 GlobalUnlock(hdata);
668 SetClipboardData(win_html_fmt, hdata);
669 CloseClipboard();
670 g_free(clipboard);
671 }
672 #endif
673
674 if (imhtml->editable)
675 gtk_text_buffer_delete_selection(imhtml->text_buffer, FALSE, FALSE);
676 g_signal_stop_emission_by_name(imhtml, "cut-clipboard");
677 }
678
633 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) 679 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data)
634 { 680 {
635 char *text; 681 char *text;
636 guint16 c; 682 guint16 c;
637 GtkIMHtml *imhtml = data; 683 GtkIMHtml *imhtml = data;
638 GtkTextIter iter; 684 GtkTextIter iter;
685 GtkIMHtmlOptions flags = GTK_IMHTML_NO_NEWLINE;
686 gboolean plaintext = FALSE;
639 687
640 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml))) 688 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml)))
641 return; 689 return;
642 690
643 #ifdef _WIN32 691 #ifdef _WIN32
666 GlobalUnlock(hdata); 714 GlobalUnlock(hdata);
667 CloseClipboard(); 715 CloseClipboard();
668 } else 716 } else
669 #endif 717 #endif
670 if (selection_data->length < 0) { 718 if (selection_data->length < 0) {
719 char *tmp;
671 text = gtk_clipboard_wait_for_text(clipboard); 720 text = gtk_clipboard_wait_for_text(clipboard);
721 flags = 0;
722 plaintext = TRUE;
672 723
673 if (text == NULL) 724 if (text == NULL)
674 return; 725 return;
675 726
727 tmp = gaim_escape_html(text);
728 g_free(text);
729 text = tmp;
676 } else { 730 } else {
677 text = g_malloc((selection_data->format / 8) * selection_data->length); 731 text = g_malloc((selection_data->format / 8) * selection_data->length);
678 memcpy(text, selection_data->data, selection_data->length * (selection_data->format / 8)); 732 memcpy(text, selection_data->data, selection_data->length * (selection_data->format / 8));
679 } 733 }
680 734
682 if (c == 0xfeff) { 736 if (c == 0xfeff) {
683 /* This is UCS2 */ 737 /* This is UCS2 */
684 char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL); 738 char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL);
685 g_free(text); 739 g_free(text);
686 text = utf8; 740 text = utf8;
687 } 741 if (!text) {
688 if (!imhtml->wbfo) 742 gaim_debug_warning("gtkimhtml", "g_convert failed in paste_received_cb\n");
689 gtk_imhtml_close_tags(imhtml); 743 return;
744 }
745 }
746
747 if (!(*text) || !g_utf8_validate(text, -1, NULL)) {
748 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in paste_received_cb\n");
749 g_free(text);
750 return;
751 }
752
690 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer)); 753 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer));
691 gtk_imhtml_insert_html_at_iter(imhtml, text, GTK_IMHTML_NO_NEWLINE, &iter); 754 if (!imhtml->wbfo && !plaintext)
755 gtk_imhtml_close_tags(imhtml, &iter);
756 gtk_imhtml_insert_html_at_iter(imhtml, text, flags, &iter);
692 gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter); 757 gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter);
758 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), gtk_text_buffer_get_insert(imhtml->text_buffer),
759 0, FALSE, 0.0, 0.0);
693 g_free(text); 760 g_free(text);
694 } 761 }
695 762
696 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah) 763 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah)
697 { 764 {
890 GDK_ACTION_COPY); 957 GDK_ACTION_COPY);
891 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); 958 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml);
892 959
893 #if GTK_CHECK_VERSION(2,2,0) 960 #if GTK_CHECK_VERSION(2,2,0)
894 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); 961 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL);
962 g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL);
895 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); 963 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL);
896 //g_signal_connect_after(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml); 964 //g_signal_connect_after(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml);
897 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL); 965 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL);
898 #endif 966 #endif
899 967
1848 GtkIMHtmlFontDetail *font = fonts->data; 1916 GtkIMHtmlFontDetail *font = fonts->data;
1849 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); 1917 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1850 ws[0] = '\0'; wpos = 0; 1918 ws[0] = '\0'; wpos = 0;
1851 /* NEW_BIT (NEW_TEXT_BIT); */ 1919 /* NEW_BIT (NEW_TEXT_BIT); */
1852 1920
1853 if (font->face) { 1921 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) {
1854 gtk_imhtml_toggle_fontface(imhtml, NULL); 1922 gtk_imhtml_toggle_fontface(imhtml, NULL);
1855 g_free (font->face); 1923 g_free (font->face);
1856 } 1924 }
1857 if (font->fore) { 1925 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) {
1858 gtk_imhtml_toggle_forecolor(imhtml, NULL); 1926 gtk_imhtml_toggle_forecolor(imhtml, NULL);
1859 g_free (font->fore); 1927 g_free (font->fore);
1860 } 1928 }
1861 if (font->back) { 1929 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) {
1862 gtk_imhtml_toggle_backcolor(imhtml, NULL); 1930 gtk_imhtml_toggle_backcolor(imhtml, NULL);
1863 g_free (font->back); 1931 g_free (font->back);
1864 } 1932 }
1865 if (font->sml) 1933 if (font->sml)
1866 g_free (font->sml); 1934 g_free (font->sml);
1867 g_free (font); 1935 g_free (font);
1868 1936
1869 if (font->size != 3) 1937 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)))
1870 gtk_imhtml_font_set_size(imhtml, 3); 1938 gtk_imhtml_font_set_size(imhtml, 3);
1871 1939
1872 fonts = fonts->next; 1940 fonts = fonts->next;
1873 if (fonts) { 1941 if (fonts) {
1874 GtkIMHtmlFontDetail *font = fonts->data; 1942 GtkIMHtmlFontDetail *font = fonts->data;
1875 1943
1876 if (font->face) 1944 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE))
1877 gtk_imhtml_toggle_fontface(imhtml, font->face); 1945 gtk_imhtml_toggle_fontface(imhtml, font->face);
1878 if (font->fore) 1946 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR))
1879 gtk_imhtml_toggle_forecolor(imhtml, font->fore); 1947 gtk_imhtml_toggle_forecolor(imhtml, font->fore);
1880 if (font->back) 1948 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR))
1881 gtk_imhtml_toggle_backcolor(imhtml, font->back); 1949 gtk_imhtml_toggle_backcolor(imhtml, font->back);
1882 if (font->size != 3) 1950 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)))
1883 gtk_imhtml_font_set_size(imhtml, font->size); 1951 gtk_imhtml_font_set_size(imhtml, font->size);
1884 } 1952 }
1885 } 1953 }
1886 break; 1954 break;
1887 case 28: /* /A */ 1955 case 28: /* /A */
1963 font->size = 100; 2031 font->size = 100;
1964 } else if (oldfont) 2032 } else if (oldfont)
1965 font->size = oldfont->size; 2033 font->size = oldfont->size;
1966 else 2034 else
1967 font->size = 3; 2035 font->size = 3;
1968 gtk_imhtml_font_set_size(imhtml, font->size); 2036 if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK)))
2037 gtk_imhtml_font_set_size(imhtml, font->size);
1969 g_free(size); 2038 g_free(size);
1970 fonts = g_slist_prepend (fonts, font); 2039 fonts = g_slist_prepend (fonts, font);
1971 } 2040 }
1972 break; 2041 break;
1973 case 44: /* BODY (opt) */ 2042 case 44: /* BODY (opt) */
2315 g_free (ws); 2384 g_free (ws);
2316 if(bg) 2385 if(bg)
2317 g_free(bg); 2386 g_free(bg);
2318 2387
2319 if (!imhtml->wbfo) 2388 if (!imhtml->wbfo)
2320 gtk_imhtml_close_tags(imhtml); 2389 gtk_imhtml_close_tags(imhtml, iter);
2321 2390
2322 object = g_object_ref(G_OBJECT(imhtml)); 2391 object = g_object_ref(G_OBJECT(imhtml));
2323 g_signal_emit(object, signals[UPDATE_FORMAT], 0); 2392 g_signal_emit(object, signals[UPDATE_FORMAT], 0);
2324 g_object_unref(object); 2393 g_object_unref(object);
2325 2394
2654 2723
2655 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) 2724 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter)
2656 { 2725 {
2657 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; 2726 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale;
2658 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); 2727 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
2659 g_object_set_data(G_OBJECT(anchor), "text_tag", "<hr>"); 2728 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>");
2729 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n");
2660 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); 2730 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor);
2661 } 2731 }
2662 2732
2663 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) 2733 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale)
2664 { 2734 {
3332 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, strlen(smiley)); 3402 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, strlen(smiley));
3333 return; 3403 return;
3334 } 3404 }
3335 3405
3336 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); 3406 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
3337 g_object_set_data(G_OBJECT(anchor), "text_tag", unescaped); 3407 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", unescaped, g_free);
3408 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free);
3338 3409
3339 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); 3410 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped);
3340 if(annipixbuf) { 3411 if(annipixbuf) {
3341 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { 3412 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) {
3342 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); 3413 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf);
3476 } 3547 }
3477 3548
3478 3549
3479 if (c == 0xFFFC) { 3550 if (c == 0xFFFC) {
3480 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); 3551 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter);
3481 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); 3552 char *text = NULL;
3482 str = g_string_append(str, text); 3553 if (anchor)
3554 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext");
3555 if (text)
3556 str = g_string_append(str, text);
3483 } else if (c == '<') { 3557 } else if (c == '<') {
3484 str = g_string_append(str, "&lt;"); 3558 str = g_string_append(str, "&lt;");
3485 } else if (c == '>') { 3559 } else if (c == '>') {
3486 str = g_string_append(str, "&gt;"); 3560 str = g_string_append(str, "&gt;");
3487 } else if (c == '&') { 3561 } else if (c == '&') {
3533 g_queue_free(q); 3607 g_queue_free(q);
3534 g_queue_free(r); 3608 g_queue_free(r);
3535 return g_string_free(str, FALSE); 3609 return g_string_free(str, FALSE);
3536 } 3610 }
3537 3611
3538 void gtk_imhtml_close_tags(GtkIMHtml *imhtml) 3612 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter)
3539 { 3613 {
3540 GtkTextIter iter;
3541
3542 if (imhtml->edit.bold) 3614 if (imhtml->edit.bold)
3543 gtk_imhtml_toggle_bold(imhtml); 3615 gtk_imhtml_toggle_bold(imhtml);
3544 3616
3545 if (imhtml->edit.italic) 3617 if (imhtml->edit.italic)
3546 gtk_imhtml_toggle_italic(imhtml); 3618 gtk_imhtml_toggle_italic(imhtml);
3557 if (imhtml->edit.fontface) 3629 if (imhtml->edit.fontface)
3558 gtk_imhtml_toggle_fontface(imhtml, NULL); 3630 gtk_imhtml_toggle_fontface(imhtml, NULL);
3559 3631
3560 imhtml->edit.fontsize = 0; 3632 imhtml->edit.fontsize = 0;
3561 3633
3562 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); 3634 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter);
3563 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, &iter, &iter);
3564 3635
3565 } 3636 }
3566 3637
3567 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) 3638 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml)
3568 { 3639 {
3620 GtkTextChildAnchor* anchor; 3691 GtkTextChildAnchor* anchor;
3621 char *text = NULL; 3692 char *text = NULL;
3622 3693
3623 anchor = gtk_text_iter_get_child_anchor(&iter); 3694 anchor = gtk_text_iter_get_child_anchor(&iter);
3624 if (anchor) 3695 if (anchor)
3625 text = g_object_get_data(G_OBJECT(anchor), "text_tag"); 3696 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext");
3626 if (text) 3697 if (text)
3627 str = g_string_append(str, text); 3698 str = g_string_append(str, text);
3628 } else { 3699 } else {
3629 g_string_append_unichar(str, c); 3700 g_string_append_unichar(str, c);
3630 } 3701 }