comparison src/gtkimhtml.c @ 11572:7be60d01519f

[gaim-migrate @ 13840] This should be more robust when dealing with different versions of iconv - we parse out the BOM and explicitly tell iconv what to do. This was lifted from the gtkhtml source. Ethan was concerned that some iconv implementations might be confused with the naming of the explicit charsets (UCS-2LE and UCS-2BE), so we should keep that in mind if people are having problems. This fixes the problem I was having that was caused by the BOM being removed by iconv during the UCS-2 to UTF-8 conversion. There is also some distracting whitespace fixing here to obscure any mistakes that I might have made. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Tue, 27 Sep 2005 14:26:11 +0000
parents b47708f46a38
children 03cd74ca2562
comparison
equal deleted inserted replaced
11571:dd5a40c6699f 11572:7be60d01519f
548 g_object_set(G_OBJECT(tag), "foreground", "light blue", NULL); 548 g_object_set(G_OBJECT(tag), "foreground", "light blue", NULL);
549 } 549 }
550 } else { 550 } else {
551 GTK_IMHTML(imhtml)->prelit_tag = NULL; 551 GTK_IMHTML(imhtml)->prelit_tag = NULL;
552 } 552 }
553 553
554 if ((oldprelit_tag != NULL) && (GTK_IMHTML(imhtml)->prelit_tag != oldprelit_tag)) { 554 if ((oldprelit_tag != NULL) && (GTK_IMHTML(imhtml)->prelit_tag != oldprelit_tag)) {
555 gtk_widget_style_get(GTK_WIDGET(imhtml), "hyperlink-color", &norm, NULL); 555 gtk_widget_style_get(GTK_WIDGET(imhtml), "hyperlink-color", &norm, NULL);
556 if (norm) 556 if (norm)
557 g_object_set(G_OBJECT(oldprelit_tag), "foreground-gdk", norm, NULL); 557 g_object_set(G_OBJECT(oldprelit_tag), "foreground-gdk", norm, NULL);
558 else 558 else
681 681
682 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_TEXT, 682 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_TEXT,
683 event->area.x, event->area.y, &buf_x, &buf_y); 683 event->area.x, event->area.y, &buf_x, &buf_y);
684 684
685 if (GTK_IMHTML(widget)->editable || GTK_IMHTML(widget)->wbfo) { 685 if (GTK_IMHTML(widget)->editable || GTK_IMHTML(widget)->wbfo) {
686 686
687 if (GTK_IMHTML(widget)->edit.background) { 687 if (GTK_IMHTML(widget)->edit.background) {
688 gdk_color_parse(GTK_IMHTML(widget)->edit.background, &gcolor); 688 gdk_color_parse(GTK_IMHTML(widget)->edit.background, &gcolor);
689 gdk_gc_set_rgb_fg_color(gc, &gcolor); 689 gdk_gc_set_rgb_fg_color(gc, &gcolor);
690 } else { 690 } else {
691 gdk_gc_set_rgb_fg_color(gc, &(widget->style->base[GTK_WIDGET_STATE(widget)])); 691 gdk_gc_set_rgb_fg_color(gc, &(widget->style->base[GTK_WIDGET_STATE(widget)]));
692 } 692 }
693 693
694 gdk_draw_rectangle(event->window, 694 gdk_draw_rectangle(event->window,
695 gc, 695 gc,
696 TRUE, 696 TRUE,
697 visible_rect.x, visible_rect.y, visible_rect.width, visible_rect.height); 697 visible_rect.x, visible_rect.y, visible_rect.width, visible_rect.height);
698 gdk_gc_unref(gc); 698 gdk_gc_unref(gc);
699 699
700 if (GTK_WIDGET_CLASS (parent_class)->expose_event) 700 if (GTK_WIDGET_CLASS (parent_class)->expose_event)
701 return (* GTK_WIDGET_CLASS (parent_class)->expose_event) 701 return (* GTK_WIDGET_CLASS (parent_class)->expose_event)
702 (widget, event); 702 (widget, event);
703
704 return FALSE; 703 return FALSE;
705 704
706 } 705 }
707 706
708 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &start, buf_x, buf_y); 707 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &start, buf_x, buf_y);
709 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &end, 708 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(widget), &end,
710 buf_x + event->area.width, buf_y + event->area.height); 709 buf_x + event->area.width, buf_y + event->area.height);
711 710
712 711
720 for (l = tags; l; l = l->next) { 719 for (l = tags; l; l = l->next) {
721 GtkTextTag *tag = l->data; 720 GtkTextTag *tag = l->data;
722 GdkRectangle rect; 721 GdkRectangle rect;
723 GdkRectangle tag_area; 722 GdkRectangle tag_area;
724 const char *color; 723 const char *color;
725 724
726 if (strncmp(tag->name, "BACKGROUND ", 11)) 725 if (strncmp(tag->name, "BACKGROUND ", 11))
727 continue; 726 continue;
728 727
729 if (gtk_text_iter_ends_tag(&cur, tag)) 728 if (gtk_text_iter_ends_tag(&cur, tag))
730 continue; 729 continue;
752 &tag_area.y); 751 &tag_area.y);
753 752
754 rect.width = visible_rect.width; 753 rect.width = visible_rect.width;
755 if (gtk_text_iter_is_end(&cur)) 754 if (gtk_text_iter_is_end(&cur))
756 rect.height = visible_rect.y + visible_rect.height - rect.y; 755 rect.height = visible_rect.y + visible_rect.height - rect.y;
757 else 756 else
758 rect.height = tag_area.y + tag_area.height - rect.y 757 rect.height = tag_area.y + tag_area.height - rect.y
759 + gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(widget)); 758 + gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(widget));
760 759
761 color = tag->name + 11; 760 color = tag->name + 11;
762 761
763 if (!gdk_color_parse(color, &gcolor)) { 762 if (!gdk_color_parse(color, &gcolor)) {
764 gchar tmp[8]; 763 gchar tmp[8];
765 tmp[0] = '#'; 764 tmp[0] = '#';
768 if (!gdk_color_parse(tmp, &gcolor)) 767 if (!gdk_color_parse(tmp, &gcolor))
769 gdk_color_parse("white", &gcolor); 768 gdk_color_parse("white", &gcolor);
770 } 769 }
771 gdk_gc_set_rgb_fg_color(gc, &gcolor); 770 gdk_gc_set_rgb_fg_color(gc, &gcolor);
772 771
773
774 gdk_draw_rectangle(event->window, 772 gdk_draw_rectangle(event->window,
775 gc, 773 gc,
776 TRUE, 774 TRUE,
777 rect.x, rect.y, rect.width, rect.height); 775 rect.x, rect.y, rect.width, rect.height);
778 gtk_text_iter_backward_char(&cur); /* go back one, in case the end is the begining is the end 776 gtk_text_iter_backward_char(&cur); /* go back one, in case the end is the begining is the end
785 783
786 /* loop until another tag begins, or no tag begins */ 784 /* loop until another tag begins, or no tag begins */
787 while (gtk_text_iter_forward_to_tag_toggle(&cur, NULL) && 785 while (gtk_text_iter_forward_to_tag_toggle(&cur, NULL) &&
788 !gtk_text_iter_is_end(&cur) && 786 !gtk_text_iter_is_end(&cur) &&
789 !gtk_text_iter_begins_tag(&cur, NULL)); 787 !gtk_text_iter_begins_tag(&cur, NULL));
790 } 788 }
791 789
792 gdk_gc_unref(gc); 790 gdk_gc_unref(gc);
793 791
794 if (GTK_WIDGET_CLASS (parent_class)->expose_event) 792 if (GTK_WIDGET_CLASS (parent_class)->expose_event)
795 return (* GTK_WIDGET_CLASS (parent_class)->expose_event) 793 return (* GTK_WIDGET_CLASS (parent_class)->expose_event)
796 (widget, event); 794 (widget, event);
823 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 3); 821 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, 3);
824 822
825 g_signal_connect(G_OBJECT(menuitem), "activate", 823 g_signal_connect(G_OBJECT(menuitem), "activate",
826 G_CALLBACK(paste_unformatted_cb), imhtml); 824 G_CALLBACK(paste_unformatted_cb), imhtml);
827 } 825 }
826
827 static char *
828 ucs2_order(gboolean swap)
829 {
830 gboolean be;
831
832 be = G_BYTE_ORDER == G_BIG_ENDIAN;
833 be = swap ? be : !be;
834
835 if (be)
836 return "UCS-2BE";
837 else
838 return "UCS-2LE";
839
840 }
841
842 /* Convert from UCS-2 to UTF-8, stripping the BOM if one is present.*/
843 static gchar *
844 ucs2_to_utf8_with_bom_check(guchar *data, guint len) {
845 char *fromcode = NULL;
846 GError *error = NULL;
847 guint16 c;
848 gchar *utf8_ret;
849
850 /*
851 * Unicode Techinical Report 20
852 * ( http://www.unicode.org/unicode/reports/tr20/ ) says to treat an
853 * initial 0xfeff (ZWNBSP) as a byte order indicator so that is
854 * what we do. If there is no indicator assume it is in the default
855 * order
856 */
857
858 memcpy(&c, data, 2);
859 switch (c) {
860 case 0xfeff:
861 case 0xfffe:
862 fromcode = ucs2_order(c == 0xfeff);
863 data += 2;
864 len -= 2;
865 break;
866 default:
867 fromcode = "UCS-2";
868 break;
869 }
870
871 utf8_ret = g_convert(data, len, "UTF-8", fromcode, NULL, NULL, &error);
872
873 if (error) {
874 gaim_debug_warning("gtkimhtml", "g_convert error: %s\n", error->message);
875 g_error_free(error);
876 }
877 return utf8_ret;
878 }
879
828 880
829 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { 881 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) {
830 char *text; 882 char *text;
831 gboolean primary; 883 gboolean primary;
832 GtkTextIter start, end; 884 GtkTextIter start, end;
1013 } 1065 }
1014 1066
1015 if (selection_data->length >= 2 && 1067 if (selection_data->length >= 2 &&
1016 (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) { 1068 (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) {
1017 /* This is UCS-2 */ 1069 /* This is UCS-2 */
1018 char *tmp; 1070 char *utf8 = ucs2_to_utf8_with_bom_check(text, selection_data->length);
1019 char *utf8 = g_convert(text, selection_data->length, "UTF-8", "UCS-2", NULL, NULL, NULL);
1020 g_free(text); 1071 g_free(text);
1021 text = utf8; 1072 text = utf8;
1022 if (!text) { 1073 if (!text) {
1023 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in paste_received_cb\n"); 1074 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in paste_received_cb\n");
1024 return; 1075 return;
1025 } 1076 }
1026 tmp = g_utf8_next_char(text); 1077 }
1027 memmove(text, tmp, strlen(tmp) + 1); 1078
1028 }
1029
1030 if (!(*text) || !g_utf8_validate(text, -1, NULL)) { 1079 if (!(*text) || !g_utf8_validate(text, -1, NULL)) {
1031 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in paste_received_cb\n"); 1080 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in paste_received_cb\n");
1032 g_free(text); 1081 g_free(text);
1033 return; 1082 return;
1034 } 1083 }
1361 imhtml->edit.backcolor = NULL; 1410 imhtml->edit.backcolor = NULL;
1362 imhtml->edit.fontface = NULL; 1411 imhtml->edit.fontface = NULL;
1363 imhtml->edit.fontsize = 0; 1412 imhtml->edit.fontsize = 0;
1364 imhtml->edit.link = NULL; 1413 imhtml->edit.link = NULL;
1365 1414
1366 1415
1367 imhtml->scalables = NULL; 1416 imhtml->scalables = NULL;
1368 1417
1369 gtk_imhtml_set_editable(imhtml, FALSE); 1418 gtk_imhtml_set_editable(imhtml, FALSE);
1370 g_signal_connect(G_OBJECT(imhtml), "populate-popup", 1419 g_signal_connect(G_OBJECT(imhtml), "populate-popup",
1371 G_CALLBACK(hijack_menu_cb), NULL); 1420 G_CALLBACK(hijack_menu_cb), NULL);
1372 1421
1373 #ifdef _WIN32 1422 #ifdef _WIN32
1374 /* Register HTML Format as desired clipboard format */ 1423 /* Register HTML Format as desired clipboard format */
1375 win_html_fmt = RegisterClipboardFormat("HTML Format"); 1424 win_html_fmt = RegisterClipboardFormat("HTML Format");
1532 GdkDragContext *context, 1581 GdkDragContext *context,
1533 gint x, 1582 gint x,
1534 gint y, 1583 gint y,
1535 guint time) 1584 guint time)
1536 { 1585 {
1537 GdkDragAction suggested_action = 0; 1586 GdkDragAction suggested_action = 0;
1538 1587
1539 if (gtk_drag_dest_find_target (widget, context, NULL) == GDK_NONE) { 1588 if (gtk_drag_dest_find_target (widget, context, NULL) == GDK_NONE) {
1540 /* can't accept any of the offered targets */ 1589 /* can't accept any of the offered targets */
1541 } else { 1590 } else {
1542 GtkWidget *source_widget; 1591 GtkWidget *source_widget;
1543 suggested_action = context->suggested_action; 1592 suggested_action = context->suggested_action;
1544 source_widget = gtk_drag_get_source_widget (context); 1593 source_widget = gtk_drag_get_source_widget (context);
1545 if (source_widget == widget) { 1594 if (source_widget == widget) {
1547 * pressed ctrl or alt to affect available actions 1596 * pressed ctrl or alt to affect available actions
1548 */ 1597 */
1549 if ((context->actions & GDK_ACTION_MOVE) != 0) 1598 if ((context->actions & GDK_ACTION_MOVE) != 0)
1550 suggested_action = GDK_ACTION_MOVE; 1599 suggested_action = GDK_ACTION_MOVE;
1551 } 1600 }
1552 } 1601 }
1553 1602
1554 gdk_drag_status (context, suggested_action, time); 1603 gdk_drag_status (context, suggested_action, time);
1555 1604
1556 /* TRUE return means don't propagate the drag motion to parent 1605 /* TRUE return means don't propagate the drag motion to parent
1557 * widgets that may also be drop sites. 1606 * widgets that may also be drop sites.
1558 */ 1607 */
1559 return TRUE; 1608 return TRUE;
1560 } 1609 }
1561 1610
1562 static void 1611 static void
1563 gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) 1612 gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data)
1564 { 1613 {
1565 GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL); 1614 GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
1566 1615
1567 if (target != GDK_NONE) 1616 if (target != GDK_NONE)
1568 gtk_drag_get_data (widget, context, target, time); 1617 gtk_drag_get_data (widget, context, target, time);
1569 else 1618 else
1570 gtk_drag_finish (context, FALSE, FALSE, time); 1619 gtk_drag_finish (context, FALSE, FALSE, time);
1571 1620
1632 * 1681 *
1633 * See also the comment on text/html here: 1682 * See also the comment on text/html here:
1634 * http://mail.gnome.org/archives/gtk-devel-list/2001-September/msg00114.html 1683 * http://mail.gnome.org/archives/gtk-devel-list/2001-September/msg00114.html
1635 */ 1684 */
1636 if (sd->length >= 2 && !g_utf8_validate(text, sd->length - 1, NULL)) { 1685 if (sd->length >= 2 && !g_utf8_validate(text, sd->length - 1, NULL)) {
1637 utf8 = g_convert(text, sd->length, "UTF-8", "UCS-2", NULL, NULL, NULL); 1686 utf8 = ucs2_to_utf8_with_bom_check(text, sd->length);
1638 1687
1639 if (!utf8) { 1688 if (!utf8) {
1640 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n"); 1689 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n");
1641 return; 1690 return;
1642 }
1643
1644 if (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe || TRUE) {
1645 char *tmp;
1646 tmp = g_utf8_next_char(utf8);
1647 memmove(utf8, tmp, strlen(tmp) + 1);
1648 } 1691 }
1649 } else if (!(*text) || !g_utf8_validate(text, -1, NULL)) { 1692 } else if (!(*text) || !g_utf8_validate(text, -1, NULL)) {
1650 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); 1693 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n");
1651 return; 1694 return;
1652 } 1695 }
1737 if (!matched) 1780 if (!matched)
1738 break; 1781 break;
1739 1782
1740 pos = strchr (t->values->str, *amp); 1783 pos = strchr (t->values->str, *amp);
1741 } 1784 }
1742 else if (*x == '<') /* Because we're all WYSIWYG now, a '<' 1785 else if (*x == '<') /* Because we're all WYSIWYG now, a '<'
1743 * char should only appear as the start of a tag. Perhaps a safer (but costlier) 1786 * char should only appear as the start of a tag. Perhaps a safer (but costlier)
1744 * check would be to call gtk_imhtml_is_tag on it */ 1787 * check would be to call gtk_imhtml_is_tag on it */
1745 break; 1788 break;
1746 else { 1789 else {
1747 alen = 1; 1790 alen = 1;
1854 1897
1855 GtkIMHtmlSmiley *smiley; 1898 GtkIMHtmlSmiley *smiley;
1856 1899
1857 smiley = gtk_imhtml_smiley_get(imhtml,sml,text); 1900 smiley = gtk_imhtml_smiley_get(imhtml,sml,text);
1858 1901
1859 if (!smiley) 1902 if (!smiley)
1860 return NULL; 1903 return NULL;
1861 1904
1862 if (!smiley->icon && smiley->file) { 1905 if (!smiley->icon && smiley->file) {
1863 smiley->icon = gdk_pixbuf_animation_new_from_file(smiley->file, NULL); 1906 smiley->icon = gdk_pixbuf_animation_new_from_file(smiley->file, NULL);
1864 } else if (!smiley->icon && smiley->loader) { 1907 } else if (!smiley->icon && smiley->loader) {
1865 smiley->icon = gdk_pixbuf_loader_get_animation(smiley->loader); 1908 smiley->icon = gdk_pixbuf_loader_get_animation(smiley->loader);
1866 if (smiley->icon) 1909 if (smiley->icon)
1867 g_object_ref(G_OBJECT(smiley->icon)); 1910 g_object_ref(G_OBJECT(smiley->icon));
1868 } 1911 }
1869 1912
1870 return smiley->icon; 1913 return smiley->icon;
1871 } 1914 }
1872 1915
1873 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ 1916 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \
1874 *tag = g_strndup (string, strlen (x)); \ 1917 *tag = g_strndup (string, strlen (x)); \
2179 static const char *accepted_protocols[] = { 2222 static const char *accepted_protocols[] = {
2180 "http://", 2223 "http://",
2181 "https://", 2224 "https://",
2182 "ftp://" 2225 "ftp://"
2183 }; 2226 };
2184 2227
2185 static const int accepted_protocols_size = 3; 2228 static const int accepted_protocols_size = 3;
2186 2229
2187 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so 2230 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so
2188 the caller knows how long the protocol string is. */ 2231 the caller knows how long the protocol string is. */
2189 int gtk_imhtml_is_protocol(const char *text) 2232 int gtk_imhtml_is_protocol(const char *text)
2202 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming 2245 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming
2203 2246
2204 2247
2205 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :) 2248 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :)
2206 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/> 2249 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/>
2207 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz 2250 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz
2208 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add 2251 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add
2209 [20:00] <marv> Robot101: so how does the image get passed to serv_got_im() and serv_send_im()? just as the <img id="#" and then the prpl looks it up from the store? 2252 [20:00] <marv> Robot101: so how does the image get passed to serv_got_im() and serv_send_im()? just as the <img id="#" and then the prpl looks it up from the store?
2210 [20:00] <KingAnt> marv: Right 2253 [20:00] <KingAnt> marv: Right
2211 [20:00] <marv> alright 2254 [20:00] <marv> alright
2212 2255
2769 } 2812 }
2770 else if (oldfont && oldfont->face) 2813 else if (oldfont && oldfont->face)
2771 font->face = g_strdup(oldfont->face); 2814 font->face = g_strdup(oldfont->face);
2772 if (font->face && (atoi(font->face) > 100)) { 2815 if (font->face && (atoi(font->face) > 100)) {
2773 /* WTF is this? */ 2816 /* WTF is this? */
2774 /* Maybe it sets a max size on the font face? I seem to 2817 /* Maybe it sets a max size on the font face? I seem to
2775 * remember bad things happening if the font size was 2818 * remember bad things happening if the font size was
2776 * 2 billion */ 2819 * 2 billion */
2777 g_free(font->face); 2820 g_free(font->face);
2778 font->face = g_strdup("100"); 2821 font->face = g_strdup("100");
2779 } 2822 }
2780 2823
4530 4573
4531 for (sl = tags; sl; sl = sl->next) { 4574 for (sl = tags; sl; sl = sl->next) {
4532 tag = sl->data; 4575 tag = sl->data;
4533 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { 4576 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) {
4534 if (strlen(tag_to_html_end(tag)) > 0) 4577 if (strlen(tag_to_html_end(tag)) > 0)
4535 g_string_append(str, tag_to_html_start(tag)); 4578 g_string_append(str, tag_to_html_start(tag));
4536 g_queue_push_tail(q, tag); 4579 g_queue_push_tail(q, tag);
4537 } 4580 }
4538 } 4581 }
4539 g_slist_free(tags); 4582 g_slist_free(tags);
4540 4583
4544 4587
4545 for (sl = tags; sl; sl = sl->next) { 4588 for (sl = tags; sl; sl = sl->next) {
4546 tag = sl->data; 4589 tag = sl->data;
4547 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { 4590 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) {
4548 if (strlen(tag_to_html_end(tag)) > 0) 4591 if (strlen(tag_to_html_end(tag)) > 0)
4549 g_string_append(str, tag_to_html_start(tag)); 4592 g_string_append(str, tag_to_html_start(tag));
4550 g_queue_push_tail(q, tag); 4593 g_queue_push_tail(q, tag);
4551 } 4594 }
4552 } 4595 }
4553 4596
4554 4597
4557 if (anchor) { 4600 if (anchor) {
4558 char *text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext"); 4601 char *text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext");
4559 if (text) 4602 if (text)
4560 str = g_string_append(str, text); 4603 str = g_string_append(str, text);
4561 } 4604 }
4562 } else if (c == '<') { 4605 } else if (c == '<') {
4563 str = g_string_append(str, "&lt;"); 4606 str = g_string_append(str, "&lt;");
4564 } else if (c == '>') { 4607 } else if (c == '>') {
4565 str = g_string_append(str, "&gt;"); 4608 str = g_string_append(str, "&gt;");
4566 } else if (c == '&') { 4609 } else if (c == '&') {
4567 str = g_string_append(str, "&amp;"); 4610 str = g_string_append(str, "&amp;");
4585 if (tmp == NULL) 4628 if (tmp == NULL)
4586 break; 4629 break;
4587 4630
4588 if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0) 4631 if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0)
4589 g_queue_push_tail(r, tmp); 4632 g_queue_push_tail(r, tmp);
4590 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); 4633 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp)));
4591 } 4634 }
4592 4635
4593 if (tmp == NULL) 4636 if (tmp == NULL)
4594 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); 4637 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n");
4595 else 4638 else
4596 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); 4639 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag)));
4597 4640
4598 while ((tmp = g_queue_pop_head(r))) { 4641 while ((tmp = g_queue_pop_head(r))) {
4599 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); 4642 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp)));
4600 g_queue_push_tail(q, tmp); 4643 g_queue_push_tail(q, tmp);