comparison src/gtkimhtml.c @ 8677:cc2ce209cc46

[gaim-migrate @ 9430] marv's patch for GtkIMHtml. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Sat, 17 Apr 2004 13:58:29 +0000
parents 44d6285a87af
children e2e56231023c
comparison
equal deleted inserted replaced
8676:e096d797d958 8677:cc2ce209cc46
61 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD 61 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD
62 #endif 62 #endif
63 63
64 #define TOOLTIP_TIMEOUT 500 64 #define TOOLTIP_TIMEOUT 500
65 65
66 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
66 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); 67 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
67 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); 68 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length);
68 void gtk_imhtml_close_tags(GtkIMHtml *imhtml); 69 void gtk_imhtml_close_tags(GtkIMHtml *imhtml);
69 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); 70 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml);
71 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml);
70 72
71 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a 73 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a
72 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ 74 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */
73 #define MAX_FONT_SIZE 7 75 #define MAX_FONT_SIZE 7
74 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) 76 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1])
75 static gdouble _point_sizes [] = { .69444444, .8333333, 1, 1.2, 1.44, 1.728, 2.0736}; 77 static gdouble _point_sizes [] = { .69444444, .8333333, 1, 1.2, 1.44, 1.728, 2.0736};
76 78
77 enum { 79 enum {
78 TARGET_HTML, 80 TARGET_HTML,
79 TARGET_UTF8_STRING, 81 TARGET_UTF8_STRING,
80 TARGET_COMPOUND_TEXT, 82 TARGET_COMPOUND_TEXT,
81 TARGET_STRING, 83 TARGET_STRING,
82 TARGET_TEXT 84 TARGET_TEXT
83 }; 85 };
382 /* 384 /*
383 * I'm adding some keyboard shortcuts too. 385 * I'm adding some keyboard shortcuts too.
384 */ 386 */
385 387
386 gboolean gtk_key_pressed_cb(GtkIMHtml *imhtml, GdkEventKey *event, gpointer data) 388 gboolean gtk_key_pressed_cb(GtkIMHtml *imhtml, GdkEventKey *event, gpointer data)
387 { 389 {
388 char buf[7]; 390 char buf[7];
389 buf[0] = '\0'; 391 buf[0] = '\0';
390 392
391 if (event->state & GDK_CONTROL_MASK) 393 if (event->state & GDK_CONTROL_MASK)
392 switch (event->keyval) { 394 switch (event->keyval) {
393 #if (!GTK_CHECK_VERSION(2,2,0)) 395 #if (!GTK_CHECK_VERSION(2,2,0))
394 case 'a': 396 case 'a':
395 return TRUE; 397 return TRUE;
396 break; 398 break;
397 399
398 case GDK_Home: 400 case GDK_Home:
399 return TRUE; 401 return TRUE;
400 break; 402 break;
401 403
402 case GDK_End: 404 case GDK_End:
458 case '+': 460 case '+':
459 if (imhtml->format_functions & GTK_IMHTML_GROW) 461 if (imhtml->format_functions & GTK_IMHTML_GROW)
460 gtk_imhtml_font_grow(imhtml); 462 gtk_imhtml_font_grow(imhtml);
461 return TRUE; 463 return TRUE;
462 break; 464 break;
463 465
464 case '1': strcpy(buf, ":-)"); break; 466 case '1': strcpy(buf, ":-)"); break;
465 case '2': strcpy(buf, ":-("); break; 467 case '2': strcpy(buf, ":-("); break;
466 case '3': strcpy(buf, ";-)"); break; 468 case '3': strcpy(buf, ";-)"); break;
467 case '4': strcpy(buf, ":-P"); break; 469 case '4': strcpy(buf, ":-P"); break;
468 case '5': strcpy(buf, "=-O"); break; 470 case '5': strcpy(buf, "=-O"); break;
479 case '*': strcpy(buf, ":-D"); break; 481 case '*': strcpy(buf, ":-D"); break;
480 } 482 }
481 if (*buf && imhtml->smiley_shortcuts) { 483 if (*buf && imhtml->smiley_shortcuts) {
482 gtk_imhtml_insert_smiley(imhtml, imhtml->protocol_name, buf); 484 gtk_imhtml_insert_smiley(imhtml, imhtml->protocol_name, buf);
483 return TRUE; 485 return TRUE;
484 } 486 }
485 return FALSE; 487 return FALSE;
486 } 488 }
487 489
488 #if GTK_CHECK_VERSION(2,2,0) 490 #if GTK_CHECK_VERSION(2,2,0)
489 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { 491 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) {
508 selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL); 510 selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL);
509 gtk_selection_data_set (selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len); 511 gtk_selection_data_set (selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len);
510 g_string_free(str, TRUE); 512 g_string_free(str, TRUE);
511 g_free(selection); 513 g_free(selection);
512 } else { 514 } else {
513 text = gtk_text_buffer_get_text(imhtml->text_buffer, &start, &end, FALSE); 515 text = gtk_imhtml_get_text(imhtml, &start, &end);
514 gtk_selection_data_set_text(selection_data, text, strlen(text)); 516 gtk_selection_data_set_text(selection_data, text, strlen(text));
515 } 517 }
516 g_free(text); 518 g_free(text);
517 } 519 }
518 520
530 gtk_text_buffer_move_mark (imhtml->text_buffer, 532 gtk_text_buffer_move_mark (imhtml->text_buffer,
531 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"), 533 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"),
532 &insert); 534 &insert);
533 } 535 }
534 536
535 static void copy_clipboard_cb(GtkIMHtml *imhtml, GtkClipboard *clipboard) 537 static void copy_clipboard_cb(GtkIMHtml *imhtml, gpointer unused)
536 { 538 {
537 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), 539 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
538 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), 540 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
539 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, 541 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
540 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); 542 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
545 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) 547 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data)
546 { 548 {
547 char *text; 549 char *text;
548 guint16 c; 550 guint16 c;
549 GtkIMHtml *imhtml = data; 551 GtkIMHtml *imhtml = data;
552 GtkTextIter iter;
550 553
551 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml))) 554 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml)))
552 return; 555 return;
553 556
554 if (selection_data->length < 0) { 557 if (selection_data->length < 0) {
567 /* This is UCS2 */ 570 /* This is UCS2 */
568 char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL); 571 char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL);
569 g_free(text); 572 g_free(text);
570 text = utf8; 573 text = utf8;
571 } 574 }
572 gtk_imhtml_close_tags(imhtml); 575 if (!imhtml->wbfo)
573 gtk_imhtml_append_text_with_images(imhtml, text, GTK_IMHTML_NO_NEWLINE, NULL); 576 gtk_imhtml_close_tags(imhtml);
577 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer));
578 gtk_imhtml_insert_html_at_iter(imhtml, text, GTK_IMHTML_NO_NEWLINE, &iter);
579 gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter);
574 } 580 }
575 581
576 582
577 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah) 583 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah)
578 { 584 {
581 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), 587 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE),
582 paste_received_cb, imhtml); 588 paste_received_cb, imhtml);
583 g_signal_stop_emission_by_name(imhtml, "paste-clipboard"); 589 g_signal_stop_emission_by_name(imhtml, "paste-clipboard");
584 } 590 }
585 591
586 static gboolean button_release_cb(GtkIMHtml *imhtml, GdkEventButton event, gpointer the_foibles_of_man) 592 static void imhtml_realized_remove_primary(GtkIMHtml *imhtml, gpointer unused)
587 { 593 {
588 GtkClipboard *clipboard; 594 gtk_text_buffer_remove_selection_clipboard(GTK_IMHTML(imhtml)->text_buffer,
589 if (event.button == 1) { 595 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY));
590 if ((clipboard = gtk_widget_get_clipboard (GTK_WIDGET (imhtml), 596
591 GDK_SELECTION_PRIMARY))) 597 }
592 gtk_text_buffer_remove_selection_clipboard (imhtml->text_buffer, clipboard); 598
599 #endif
600
601 static void mark_set_so_update_selection_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml)
602 {
603 if (gtk_text_buffer_get_selection_bounds(buffer, NULL, NULL)) {
593 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY), 604 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY),
594 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), 605 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
595 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, 606 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
596 (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml)); 607 (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml));
597 } 608 }
609 }
610
611 /* does this go in the #ifdef too? I need to keep track of which functions are 2.2 only */
612 /* adapted from gtktextview.c */
613 static gboolean gtk_imhtml_button_press_event(GtkIMHtml *imhtml, GdkEventButton *event, gpointer unused)
614 {
615 if (event->button == 2) {
616 int x, y;
617 GtkTextIter iter;
618 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY);
619
620 if (!imhtml->editable)
621 return FALSE;
622
623 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml),
624 GTK_TEXT_WINDOW_TEXT,
625 event->x,
626 event->y,
627 &x,
628 &y);
629 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y);
630 gtk_text_buffer_place_cursor(imhtml->text_buffer, &iter);
631
632 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE),
633 paste_received_cb, imhtml);
634
635 return TRUE;
636 }
637
598 return FALSE; 638 return FALSE;
599 } 639 }
600 #endif
601
602 640
603 static GtkTextViewClass *parent_class = NULL; 641 static GtkTextViewClass *parent_class = NULL;
604 642
605 static void 643 static void
606 gtk_imhtml_finalize (GObject *object) 644 gtk_imhtml_finalize (GObject *object)
611 g_hash_table_destroy(imhtml->smiley_data); 649 g_hash_table_destroy(imhtml->smiley_data);
612 gtk_smiley_tree_destroy(imhtml->default_smilies); 650 gtk_smiley_tree_destroy(imhtml->default_smilies);
613 gdk_cursor_unref(imhtml->hand_cursor); 651 gdk_cursor_unref(imhtml->hand_cursor);
614 gdk_cursor_unref(imhtml->arrow_cursor); 652 gdk_cursor_unref(imhtml->arrow_cursor);
615 gdk_cursor_unref(imhtml->text_cursor); 653 gdk_cursor_unref(imhtml->text_cursor);
616 654
617 if(imhtml->tip_window){ 655 if(imhtml->tip_window){
618 gtk_widget_destroy(imhtml->tip_window); 656 gtk_widget_destroy(imhtml->tip_window);
619 } 657 }
620 if(imhtml->tip_timer) 658 if(imhtml->tip_timer)
621 gtk_timeout_remove(imhtml->tip_timer); 659 gtk_timeout_remove(imhtml->tip_timer);
686 static void gtk_imhtml_init (GtkIMHtml *imhtml) 724 static void gtk_imhtml_init (GtkIMHtml *imhtml)
687 { 725 {
688 GtkTextIter iter; 726 GtkTextIter iter;
689 imhtml->text_buffer = gtk_text_buffer_new(NULL); 727 imhtml->text_buffer = gtk_text_buffer_new(NULL);
690 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); 728 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter);
691 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); 729 imhtml->scrollpoint = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE);
692 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); 730 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer);
693 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); 731 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR);
694 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); 732 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5);
733 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(imhtml), 2);
734 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(imhtml), 2);
695 /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/ 735 /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/
696 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ 736 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/
697 737
698 /* These tags will be used often and can be reused--we create them on init and then apply them by name 738 /* These tags will be used often and can be reused--we create them on init and then apply them by name
699 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ 739 * other tags (color, size, face, etc.) will have to be created and applied dynamically */
703 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); 743 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL);
704 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); 744 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL);
705 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); 745 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL);
706 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); 746 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL);
707 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); 747 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL);
708 gtk_text_buffer_create_tag(imhtml->text_buffer, "LINK", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); 748
709 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ 749 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */
710 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); 750 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2);
711 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); 751 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR);
712 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); 752 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM);
713 753
720 760
721 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); 761 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL);
722 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); 762 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL);
723 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); 763 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL);
724 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); 764 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL);
765 g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL);
766 g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml);
725 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); 767 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml);
726 768
727 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0, 769 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0,
728 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry), 770 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry),
729 GDK_ACTION_COPY); 771 GDK_ACTION_COPY);
730 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); 772 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml);
731 773
732 #if GTK_CHECK_VERSION(2,2,0) 774 #if GTK_CHECK_VERSION(2,2,0)
733 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); 775 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL);
734 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); 776 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL);
735 g_signal_connect(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml); 777 //g_signal_connect_after(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml);
778 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL);
736 #endif 779 #endif
780
781 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set",
782 G_CALLBACK(mark_set_so_update_selection_cb), imhtml);
783
737 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); 784 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK);
738 785
739 imhtml->tip = NULL; 786 imhtml->tip = NULL;
740 imhtml->tip_timer = 0; 787 imhtml->tip_timer = 0;
741 imhtml->tip_window = NULL; 788 imhtml->tip_window = NULL;
742 789
743 imhtml->edit.bold = NULL; 790 imhtml->edit.bold = FALSE;
744 imhtml->edit.italic = NULL; 791 imhtml->edit.italic = FALSE;
745 imhtml->edit.underline = NULL; 792 imhtml->edit.underline = FALSE;
746 imhtml->edit.forecolor = NULL; 793 imhtml->edit.forecolor = NULL;
747 imhtml->edit.backcolor = NULL; 794 imhtml->edit.backcolor = NULL;
748 imhtml->edit.fontface = NULL; 795 imhtml->edit.fontface = NULL;
749 imhtml->edit.sizespan = NULL; 796 imhtml->edit.fontsize = 0;
750 imhtml->edit.fontsize = 3; 797 imhtml->edit.link = NULL;
751 798
752 imhtml->format_spans = NULL;
753 799
754 imhtml->scalables = NULL; 800 imhtml->scalables = NULL;
755 801
756 gtk_imhtml_set_editable(imhtml, FALSE); 802 gtk_imhtml_set_editable(imhtml, FALSE);
757 } 803 }
788 struct url_data { 834 struct url_data {
789 GObject *object; 835 GObject *object;
790 gchar *url; 836 gchar *url;
791 }; 837 };
792 838
839 static void url_data_destroy(gpointer mydata)
840 {
841 struct url_data *data = mydata;
842 g_object_unref(data->object);
843 g_free(data->url);
844 g_free(data);
845 }
846
793 static void url_open(GtkWidget *w, struct url_data *data) { 847 static void url_open(GtkWidget *w, struct url_data *data) {
794 if(!data) return; 848 if(!data) return;
795 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); 849 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url);
796 850
797 g_object_unref(data->object);
798 g_free(data->url);
799 g_free(data);
800 } 851 }
801 852
802 static void url_copy(GtkWidget *w, gchar *url) { 853 static void url_copy(GtkWidget *w, gchar *url) {
803 GtkClipboard *clipboard; 854 GtkClipboard *clipboard;
804 855
808 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); 859 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
809 gtk_clipboard_set_text(clipboard, url, -1); 860 gtk_clipboard_set_text(clipboard, url, -1);
810 } 861 }
811 862
812 /* The callback for an event on a link tag. */ 863 /* The callback for an event on a link tag. */
813 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) { 864 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, gpointer unused) {
814 GdkEventButton *event_button = (GdkEventButton *) event; 865 GdkEventButton *event_button = (GdkEventButton *) event;
815 if (GTK_IMHTML(imhtml)->editable) 866 if (GTK_IMHTML(imhtml)->editable)
816 return FALSE; 867 return FALSE;
817 if (event->type == GDK_BUTTON_RELEASE) { 868 if (event->type == GDK_BUTTON_RELEASE) {
818 if (event_button->button == 1) { 869 if (event_button->button == 1) {
819 GtkTextIter start, end; 870 GtkTextIter start, end;
820 /* we shouldn't open a URL if the user has selected something: */ 871 /* we shouldn't open a URL if the user has selected something: */
821 gtk_text_buffer_get_selection_bounds( 872 if (gtk_text_buffer_get_selection_bounds(
822 gtk_text_iter_get_buffer(arg2), &start, &end); 873 gtk_text_iter_get_buffer(arg2), &start, &end))
823 if(gtk_text_iter_get_offset(&start) !=
824 gtk_text_iter_get_offset(&end))
825 return FALSE; 874 return FALSE;
826 875
827 /* A link was clicked--we emit the "url_clicked" signal 876 /* A link was clicked--we emit the "url_clicked" signal
828 * with the URL as the argument */ 877 * with the URL as the argument */
829 g_signal_emit(imhtml, signals[URL_CLICKED], 0, url); 878 g_object_ref(G_OBJECT(tag));
879 g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url"));
880 g_object_unref(G_OBJECT(tag));
830 return FALSE; 881 return FALSE;
831 } else if(event_button->button == 3) { 882 } else if(event_button->button == 3) {
832 GtkWidget *img, *item, *menu; 883 GtkWidget *img, *item, *menu;
833 struct url_data *tempdata = g_new(struct url_data, 1); 884 struct url_data *tempdata = g_new(struct url_data, 1);
834 tempdata->object = g_object_ref(imhtml); 885 tempdata->object = g_object_ref(imhtml);
835 tempdata->url = g_strdup(url); 886 tempdata->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url"));
836 887
837 /* Don't want the tooltip around if user right-clicked on link */ 888 /* Don't want the tooltip around if user right-clicked on link */
838 if (GTK_IMHTML(imhtml)->tip_window) { 889 if (GTK_IMHTML(imhtml)->tip_window) {
839 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); 890 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window);
840 GTK_IMHTML(imhtml)->tip_window = NULL; 891 GTK_IMHTML(imhtml)->tip_window = NULL;
846 if (GTK_IMHTML(imhtml)->editable) 897 if (GTK_IMHTML(imhtml)->editable)
847 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); 898 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor);
848 else 899 else
849 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); 900 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor);
850 menu = gtk_menu_new(); 901 menu = gtk_menu_new();
902 g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", tempdata, url_data_destroy);
851 903
852 /* buttons and such */ 904 /* buttons and such */
853 905
854 if (!strncmp(url, "mailto:", 7)) 906 if (!strncmp(tempdata->url, "mailto:", 7))
855 { 907 {
856 /* Copy E-Mail Address */ 908 /* Copy E-Mail Address */
857 img = gtk_image_new_from_stock(GTK_STOCK_COPY, 909 img = gtk_image_new_from_stock(GTK_STOCK_COPY,
858 GTK_ICON_SIZE_MENU); 910 GTK_ICON_SIZE_MENU);
859 item = gtk_image_menu_item_new_with_mnemonic( 911 item = gtk_image_menu_item_new_with_mnemonic(
860 _("_Copy E-Mail Address")); 912 _("_Copy E-Mail Address"));
861 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); 913 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
862 g_signal_connect(G_OBJECT(item), "activate", 914 g_signal_connect(G_OBJECT(item), "activate",
863 G_CALLBACK(url_copy), url + 7); 915 G_CALLBACK(url_copy), tempdata->url + 7);
864 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 916 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
865 } 917 }
866 else 918 else
867 { 919 {
868 /* Copy Link Location */ 920 /* Copy Link Location */
870 GTK_ICON_SIZE_MENU); 922 GTK_ICON_SIZE_MENU);
871 item = gtk_image_menu_item_new_with_mnemonic( 923 item = gtk_image_menu_item_new_with_mnemonic(
872 _("_Copy Link Location")); 924 _("_Copy Link Location"));
873 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); 925 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
874 g_signal_connect(G_OBJECT(item), "activate", 926 g_signal_connect(G_OBJECT(item), "activate",
875 G_CALLBACK(url_copy), url); 927 G_CALLBACK(url_copy), tempdata->url);
876 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 928 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
877 929
878 /* Open Link in Browser */ 930 /* Open Link in Browser */
879 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, 931 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO,
880 GTK_ICON_SIZE_MENU); 932 GTK_ICON_SIZE_MENU);
914 links = g_strsplit(sd->data, "\n", 0); 966 links = g_strsplit(sd->data, "\n", 0);
915 while((link = *links++) != NULL){ 967 while((link = *links++) != NULL){
916 if(gaim_str_has_prefix(link, "http://") || 968 if(gaim_str_has_prefix(link, "http://") ||
917 gaim_str_has_prefix(link, "https://") || 969 gaim_str_has_prefix(link, "https://") ||
918 gaim_str_has_prefix(link, "ftp://")){ 970 gaim_str_has_prefix(link, "ftp://")){
919 gtk_imhtml_insert_link(imhtml, link, link); 971 gtk_imhtml_insert_link(imhtml, gtk_text_buffer_get_insert(imhtml->text_buffer), link, link);
920 } else if (link=='\0') { 972 } else if (link=='\0') {
921 /* Ignore blank lines */ 973 /* Ignore blank lines */
922 } else { 974 } else {
923 /* Special reasons, aka images being put in via other tag, etc. */ 975 /* Special reasons, aka images being put in via other tag, etc. */
924 } 976 }
1406 } 1458 }
1407 } 1459 }
1408 return 0; 1460 return 0;
1409 } 1461 }
1410 1462
1411 GString* gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, 1463 /*
1412 const gchar *text, 1464 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming
1413 GtkIMHtmlOptions options, 1465
1414 GSList *images) 1466
1415 { 1467 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :)
1416 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 1468 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/>
1417 GtkTextIter insert; 1469 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz
1470 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add
1471 [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?
1472 [20:00] <KingAnt> marv: Right
1473 [20:00] <marv> alright
1474
1475 Here's my plan with IMImages. make gtk_imhtml_[append|insert]_text_with_images instead just
1476 gtkimhtml_[append|insert]_text (hrm maybe it should be called html instead of text), add a
1477 function for gaim to register for look up images, i.e. gtk_imhtml_set_get_img_fnc, so that
1478 images can be looked up like that, instead of passing a GSList of them.
1479 */
1480
1481 void gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml,
1482 const gchar *text,
1483 GtkIMHtmlOptions options,
1484 GSList *unused)
1485 {
1486 GtkTextIter iter, ins, sel;
1487 GdkRectangle rect;
1488 int y, height, ins_offset = 0, sel_offset = 0;
1489 gboolean fixins = FALSE, fixsel = FALSE;
1490
1491 g_return_if_fail (imhtml != NULL);
1492 g_return_if_fail (GTK_IS_IMHTML (imhtml));
1493 g_return_if_fail (text != NULL);
1494
1495
1496 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter);
1497 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, gtk_text_buffer_get_insert(imhtml->text_buffer));
1498 if (gtk_text_iter_equal(&iter, &ins) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) {
1499 fixins = TRUE;
1500 ins_offset = gtk_text_iter_get_offset(&ins);
1501 }
1502
1503 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &sel, gtk_text_buffer_get_selection_bound(imhtml->text_buffer));
1504 if (gtk_text_iter_equal(&iter, &sel) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) {
1505 fixsel = TRUE;
1506 sel_offset = gtk_text_iter_get_offset(&sel);
1507 }
1508
1509 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
1510 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height);
1511
1512
1513 if(((y + height) - (rect.y + rect.height)) > height
1514 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){
1515 options |= GTK_IMHTML_NO_SCROLL;
1516 }
1517
1518 gtk_imhtml_insert_html_at_iter(imhtml, text, options, &iter);
1519
1520 if (fixins) {
1521 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins, ins_offset);
1522 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_insert(imhtml->text_buffer), &ins);
1523 }
1524
1525 if (fixsel) {
1526 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &sel, sel_offset);
1527 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_selection_bound(imhtml->text_buffer), &sel);
1528 }
1529
1530 if (!(options & GTK_IMHTML_NO_SCROLL)) {
1531 /* If this seems backwards at first glance, well it's not.
1532 * It means scroll such that the mark is closest to the top,
1533 * and closest to the right as possible. Remember kids, you have
1534 * to scroll left to move a given spot closest to the right,
1535 * and scroll down to move a spot closest to the top.
1536 */
1537 gtk_text_iter_set_line_offset(&iter, 0);
1538 gtk_text_buffer_move_mark(imhtml->text_buffer, imhtml->scrollpoint, &iter);
1539 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), imhtml->scrollpoint,
1540 0, TRUE, 1.0, 0.0);
1541 }
1542 }
1543
1544 void gtk_imhtml_insert_html_at_iter(GtkIMHtml *imhtml,
1545 const gchar *text,
1546 GtkIMHtmlOptions options,
1547 GtkTextIter *iter)
1548 {
1418 GdkRectangle rect; 1549 GdkRectangle rect;
1419 gint pos = 0; 1550 gint pos = 0;
1420 GString *str = NULL;
1421 GtkTextIter iter;
1422 GtkTextMark *mark;
1423 gchar *ws; 1551 gchar *ws;
1424 gchar *tag; 1552 gchar *tag;
1425 gchar *url = NULL;
1426 gchar *bg = NULL; 1553 gchar *bg = NULL;
1427 gint len; 1554 gint len;
1428 gint tlen, smilelen, wpos=0; 1555 gint tlen, smilelen, wpos=0;
1429 gint type; 1556 gint type;
1430 const gchar *c; 1557 const gchar *c;
1441 pre = 0; 1568 pre = 0;
1442 1569
1443 GSList *fonts = NULL; 1570 GSList *fonts = NULL;
1444 GObject *object; 1571 GObject *object;
1445 GtkIMHtmlScalable *scalable = NULL; 1572 GtkIMHtmlScalable *scalable = NULL;
1446 int y, height; 1573
1447 1574 g_return_if_fail (imhtml != NULL);
1448 g_return_val_if_fail (imhtml != NULL, NULL); 1575 g_return_if_fail (GTK_IS_IMHTML (imhtml));
1449 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); 1576 g_return_if_fail (text != NULL);
1450 g_return_val_if_fail (text != NULL, NULL);
1451 c = text; 1577 c = text;
1452 len = strlen(text); 1578 len = strlen(text);
1453 ws = g_malloc(len + 1); 1579 ws = g_malloc(len + 1);
1454 ws[0] = 0; 1580 ws[0] = 0;
1455
1456 if (options & GTK_IMHTML_RETURN_LOG)
1457 str = g_string_new("");
1458
1459 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &insert, ins);
1460
1461 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter);
1462 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE);
1463
1464 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
1465 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height);
1466
1467 #if GTK_CHECK_VERSION(2,2,0)
1468 gtk_imhtml_primary_clipboard_clear(NULL, imhtml);
1469 #endif
1470 gtk_text_buffer_move_mark (imhtml->text_buffer,
1471 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"),
1472 &iter);
1473
1474 if(((y + height) - (rect.y + rect.height)) > height
1475 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){
1476 options |= GTK_IMHTML_NO_SCROLL;
1477 }
1478 1581
1479 while (pos < len) { 1582 while (pos < len) {
1480 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { 1583 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) {
1481 c++; 1584 c++;
1482 pos++; 1585 pos++;
1484 switch (type) 1587 switch (type)
1485 { 1588 {
1486 case 1: /* B */ 1589 case 1: /* B */
1487 case 2: /* BOLD */ 1590 case 2: /* BOLD */
1488 case 54: /* STRONG */ 1591 case 54: /* STRONG */
1489 if (url) 1592
1490 gtk_imhtml_insert_link(imhtml, url, ws); 1593 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1491 else 1594
1492 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); 1595 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD))
1493 if (bold == 0)
1494 gtk_imhtml_toggle_bold(imhtml); 1596 gtk_imhtml_toggle_bold(imhtml);
1495 bold++; 1597 bold++;
1496 ws[0] = '\0'; wpos = 0; 1598 ws[0] = '\0'; wpos = 0;
1497 break; 1599 break;
1498 case 3: /* /B */ 1600 case 3: /* /B */
1499 case 4: /* /BOLD */ 1601 case 4: /* /BOLD */
1500 case 55: /* /STRONG */ 1602 case 55: /* /STRONG */
1501 if (url) 1603 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1502 gtk_imhtml_insert_link(imhtml, url, ws);
1503 else
1504 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1505 ws[0] = '\0'; wpos = 0; 1604 ws[0] = '\0'; wpos = 0;
1506 1605
1507 if (bold) 1606 if (bold)
1508 bold--; 1607 bold--;
1509 if (bold == 0) 1608 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD) && !imhtml->wbfo)
1510 gtk_imhtml_toggle_bold(imhtml); 1609 gtk_imhtml_toggle_bold(imhtml);
1511 break; 1610 break;
1512 case 5: /* I */ 1611 case 5: /* I */
1513 case 6: /* ITALIC */ 1612 case 6: /* ITALIC */
1514 case 52: /* EM */ 1613 case 52: /* EM */
1515 if (url) 1614 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1516 gtk_imhtml_insert_link(imhtml, url, ws);
1517 else
1518 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1519 ws[0] = '\0'; wpos = 0; 1615 ws[0] = '\0'; wpos = 0;
1520 if (italics == 0) 1616 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC))
1521 gtk_imhtml_toggle_italic(imhtml); 1617 gtk_imhtml_toggle_italic(imhtml);
1522 italics++; 1618 italics++;
1523 break; 1619 break;
1524 case 7: /* /I */ 1620 case 7: /* /I */
1525 case 8: /* /ITALIC */ 1621 case 8: /* /ITALIC */
1526 case 53: /* /EM */ 1622 case 53: /* /EM */
1527 if (url) 1623 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1528 gtk_imhtml_insert_link(imhtml, url, ws);
1529 else
1530 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1531 ws[0] = '\0'; wpos = 0; 1624 ws[0] = '\0'; wpos = 0;
1532 if (italics) 1625 if (italics)
1533 italics--; 1626 italics--;
1534 if (italics == 0) 1627 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC) && !imhtml->wbfo)
1535 gtk_imhtml_toggle_italic(imhtml); 1628 gtk_imhtml_toggle_italic(imhtml);
1536 break; 1629 break;
1537 case 9: /* U */ 1630 case 9: /* U */
1538 case 10: /* UNDERLINE */ 1631 case 10: /* UNDERLINE */
1539 if (url) 1632 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1540 gtk_imhtml_insert_link(imhtml, url, ws);
1541 else
1542 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1543 ws[0] = '\0'; wpos = 0; 1633 ws[0] = '\0'; wpos = 0;
1544 if (underline == 0) 1634 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE))
1545 gtk_imhtml_toggle_underline(imhtml); 1635 gtk_imhtml_toggle_underline(imhtml);
1546 underline++; 1636 underline++;
1547 break; 1637 break;
1548 case 11: /* /U */ 1638 case 11: /* /U */
1549 case 12: /* /UNDERLINE */ 1639 case 12: /* /UNDERLINE */
1550 if (url) 1640 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1551 gtk_imhtml_insert_link(imhtml, url, ws);
1552 else
1553 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1554 ws[0] = '\0'; wpos = 0; 1641 ws[0] = '\0'; wpos = 0;
1555 if (underline) 1642 if (underline)
1556 underline--; 1643 underline--;
1557 if (underline == 0) 1644 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE) && !imhtml->wbfo)
1558 gtk_imhtml_toggle_underline(imhtml); 1645 gtk_imhtml_toggle_underline(imhtml);
1559 break; 1646 break;
1560 case 13: /* S */ 1647 case 13: /* S */
1561 case 14: /* STRIKE */ 1648 case 14: /* STRIKE */
1562 /* NEW_BIT (NEW_TEXT_BIT); */ 1649 /* FIXME: reimplement this */
1563 strike++; 1650 strike++;
1564 break; 1651 break;
1565 case 15: /* /S */ 1652 case 15: /* /S */
1566 case 16: /* /STRIKE */ 1653 case 16: /* /STRIKE */
1567 /* NEW_BIT (NEW_TEXT_BIT); */ 1654 /* FIXME: reimplement this */
1568 if (strike) 1655 if (strike)
1569 strike--; 1656 strike--;
1570 break; 1657 break;
1571 case 17: /* SUB */ 1658 case 17: /* SUB */
1572 /* NEW_BIT (NEW_TEXT_BIT); */ 1659 /* FIXME: reimpliment this */
1573 sub++; 1660 sub++;
1574 break; 1661 break;
1575 case 18: /* /SUB */ 1662 case 18: /* /SUB */
1576 /* NEW_BIT (NEW_TEXT_BIT); */ 1663 /* FIXME: reimpliment this */
1577 if (sub) 1664 if (sub)
1578 sub--; 1665 sub--;
1579 break; 1666 break;
1580 case 19: /* SUP */ 1667 case 19: /* SUP */
1581 /* NEW_BIT (NEW_TEXT_BIT); */ 1668 /* FIXME: reimplement this */
1582 sup++; 1669 sup++;
1583 break; 1670 break;
1584 case 20: /* /SUP */ 1671 case 20: /* /SUP */
1585 /* NEW_BIT (NEW_TEXT_BIT); */ 1672 /* FIXME: reimplement this */
1586 if (sup) 1673 if (sup)
1587 sup--; 1674 sup--;
1588 break; 1675 break;
1589 case 21: /* PRE */ 1676 case 21: /* PRE */
1590 /* NEW_BIT (NEW_TEXT_BIT); */ 1677 /* FIXME: reimplement this */
1591 pre++; 1678 pre++;
1592 break; 1679 break;
1593 case 22: /* /PRE */ 1680 case 22: /* /PRE */
1594 /* NEW_BIT (NEW_TEXT_BIT); */ 1681 /* FIXME: reimplement this */
1595 if (pre) 1682 if (pre)
1596 pre--; 1683 pre--;
1597 break; 1684 break;
1598 case 23: /* TITLE */ 1685 case 23: /* TITLE */
1599 /* NEW_BIT (NEW_TEXT_BIT); */ 1686 /* FIXME: what was this supposed to do anyway? */
1600 title++; 1687 title++;
1601 break; 1688 break;
1602 case 24: /* /TITLE */ 1689 case 24: /* /TITLE */
1690 /* FIXME: make this undo whatever 23 was supposed to do */
1603 if (title) { 1691 if (title) {
1604 if (options & GTK_IMHTML_NO_TITLE) { 1692 if (options & GTK_IMHTML_NO_TITLE) {
1605 wpos = 0; 1693 wpos = 0;
1606 ws [wpos] = '\0'; 1694 ws [wpos] = '\0';
1607 } 1695 }
1611 case 25: /* BR */ 1699 case 25: /* BR */
1612 case 58: /* BR/ */ 1700 case 58: /* BR/ */
1613 case 61: /* BR (opt) */ 1701 case 61: /* BR (opt) */
1614 ws[wpos] = '\n'; 1702 ws[wpos] = '\n';
1615 wpos++; 1703 wpos++;
1616 /* NEW_BIT (NEW_TEXT_BIT); */
1617 break; 1704 break;
1618 case 26: /* HR */ 1705 case 26: /* HR */
1619 case 42: /* HR (opt) */ 1706 case 42: /* HR (opt) */
1620 ws[wpos++] = '\n'; 1707 ws[wpos++] = '\n';
1621 if (url) 1708 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1622 gtk_imhtml_insert_link(imhtml, url, ws); 1709
1623 else
1624 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1625 scalable = gtk_imhtml_hr_new(); 1710 scalable = gtk_imhtml_hr_new();
1626 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); 1711 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
1627 scalable->add_to(scalable, imhtml, &iter); 1712 scalable->add_to(scalable, imhtml, iter);
1628 scalable->scale(scalable, rect.width, rect.height); 1713 scalable->scale(scalable, rect.width, rect.height);
1629 imhtml->scalables = g_list_append(imhtml->scalables, scalable); 1714 imhtml->scalables = g_list_append(imhtml->scalables, scalable);
1630 ws[0] = '\0'; wpos = 0; 1715 ws[0] = '\0'; wpos = 0;
1631 ws[wpos++] = '\n'; 1716 ws[wpos++] = '\n';
1632 1717
1633 break; 1718 break;
1634 case 27: /* /FONT */ 1719 case 27: /* /FONT */
1635 if (fonts) { 1720 if (fonts && !imhtml->wbfo) {
1636 GtkIMHtmlFontDetail *font = fonts->data; 1721 GtkIMHtmlFontDetail *font = fonts->data;
1637 if (url) 1722 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1638 gtk_imhtml_insert_link(imhtml, url, ws);
1639 else
1640 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1641 ws[0] = '\0'; wpos = 0; 1723 ws[0] = '\0'; wpos = 0;
1642 /* NEW_BIT (NEW_TEXT_BIT); */ 1724 /* NEW_BIT (NEW_TEXT_BIT); */
1643 1725
1644 if (font->face) { 1726 if (font->face) {
1645 gtk_imhtml_toggle_fontface(imhtml, NULL); 1727 gtk_imhtml_toggle_fontface(imhtml, NULL);
1646 g_free (font->face); 1728 g_free (font->face);
1647 } 1729 }
1648 if (font->fore) { 1730 if (font->fore) {
1661 gtk_imhtml_font_set_size(imhtml, 3); 1743 gtk_imhtml_font_set_size(imhtml, 3);
1662 1744
1663 fonts = fonts->next; 1745 fonts = fonts->next;
1664 if (fonts) { 1746 if (fonts) {
1665 GtkIMHtmlFontDetail *font = fonts->data; 1747 GtkIMHtmlFontDetail *font = fonts->data;
1666 1748
1667 if (font->face) 1749 if (font->face)
1668 gtk_imhtml_toggle_fontface(imhtml, font->face); 1750 gtk_imhtml_toggle_fontface(imhtml, font->face);
1669 if (font->fore) 1751 if (font->fore)
1670 gtk_imhtml_toggle_forecolor(imhtml, font->fore); 1752 gtk_imhtml_toggle_forecolor(imhtml, font->fore);
1671 if (font->back) 1753 if (font->back)
1672 gtk_imhtml_toggle_backcolor(imhtml, font->back); 1754 gtk_imhtml_toggle_backcolor(imhtml, font->back);
1673 if (font->size != 3) 1755 if (font->size != 3)
1674 gtk_imhtml_font_set_size(imhtml, font->size); 1756 gtk_imhtml_font_set_size(imhtml, font->size);
1675 } 1757 }
1676 } 1758 }
1677 break; 1759 break;
1678 case 28: /* /A */ 1760 case 28: /* /A */
1679 if (url) { 1761 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1680 gtk_imhtml_insert_link(imhtml, url, ws); 1762 gtk_imhtml_toggle_link(imhtml, NULL);
1681 g_free(url); 1763 ws[0] = '\0'; wpos = 0;
1682 ws[0] = '\0'; wpos = 0;
1683 url = NULL;
1684 ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
1685 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
1686 }
1687 break; 1764 break;
1688 1765
1689 case 29: /* P */ 1766 case 29: /* P */
1690 case 30: /* /P */ 1767 case 30: /* /P */
1691 case 31: /* H3 */ 1768 case 31: /* H3 */
1710 size = gtk_imhtml_get_html_opt (tag, "SIZE="); 1787 size = gtk_imhtml_get_html_opt (tag, "SIZE=");
1711 sml = gtk_imhtml_get_html_opt (tag, "SML="); 1788 sml = gtk_imhtml_get_html_opt (tag, "SML=");
1712 if (!(color || back || face || size || sml)) 1789 if (!(color || back || face || size || sml))
1713 break; 1790 break;
1714 1791
1715 if (url) 1792 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1716 gtk_imhtml_insert_link(imhtml, url, ws);
1717 else
1718 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1719 ws[0] = '\0'; wpos = 0; 1793 ws[0] = '\0'; wpos = 0;
1720 1794
1721 font = g_new0 (GtkIMHtmlFontDetail, 1); 1795 font = g_new0 (GtkIMHtmlFontDetail, 1);
1722 if (fonts) 1796 if (fonts)
1723 oldfont = fonts->data; 1797 oldfont = fonts->data;
1724 1798
1725 if (color && !(options & GTK_IMHTML_NO_COLOURS)) { 1799 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) {
1726 font->fore = color; 1800 font->fore = color;
1727 gtk_imhtml_toggle_forecolor(imhtml, font->fore); 1801 gtk_imhtml_toggle_forecolor(imhtml, font->fore);
1728 } 1802 }
1729 //else if (oldfont && oldfont->fore) 1803 //else if (oldfont && oldfont->fore)
1730 // font->fore = g_strdup(oldfont->fore); 1804 // font->fore = g_strdup(oldfont->fore);
1731 1805
1732 if (back && !(options & GTK_IMHTML_NO_COLOURS)) { 1806 if (back && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) {
1733 font->back = back; 1807 font->back = back;
1734 gtk_imhtml_toggle_backcolor(imhtml, font->back); 1808 gtk_imhtml_toggle_backcolor(imhtml, font->back);
1735 } 1809 }
1736 //else if (oldfont && oldfont->back) 1810 //else if (oldfont && oldfont->back)
1737 // font->back = g_strdup(oldfont->back); 1811 // font->back = g_strdup(oldfont->back);
1738 1812
1739 if (face && !(options & GTK_IMHTML_NO_FONTS)) { 1813 if (face && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) {
1740 font->face = face; 1814 font->face = face;
1741 gtk_imhtml_toggle_fontface(imhtml, font->face); 1815 gtk_imhtml_toggle_fontface(imhtml, font->face);
1742 } 1816 }
1743 //else if (oldfont && oldfont->face) 1817 //else if (oldfont && oldfont->face)
1744 // font->face = g_strdup(oldfont->face); 1818 // font->face = g_strdup(oldfont->face);
1746 if (sml) 1820 if (sml)
1747 font->sml = sml; 1821 font->sml = sml;
1748 else if (oldfont && oldfont->sml) 1822 else if (oldfont && oldfont->sml)
1749 font->sml = g_strdup(oldfont->sml); 1823 font->sml = g_strdup(oldfont->sml);
1750 1824
1751 if (size && !(options & GTK_IMHTML_NO_SIZES)) { 1825 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) {
1752 if (*size == '+') { 1826 if (*size == '+') {
1753 sscanf (size + 1, "%hd", &font->size); 1827 sscanf (size + 1, "%hd", &font->size);
1754 font->size += 3; 1828 font->size += 3;
1755 } else if (*size == '-') { 1829 } else if (*size == '-') {
1756 sscanf (size + 1, "%hd", &font->size); 1830 sscanf (size + 1, "%hd", &font->size);
1770 } 1844 }
1771 break; 1845 break;
1772 case 44: /* BODY (opt) */ 1846 case 44: /* BODY (opt) */
1773 if (!(options & GTK_IMHTML_NO_COLOURS)) { 1847 if (!(options & GTK_IMHTML_NO_COLOURS)) {
1774 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); 1848 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR=");
1775 if (bgcolor) { 1849 if (bgcolor && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) {
1776 if (url) 1850 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1777 gtk_imhtml_insert_link(imhtml, url, ws);
1778 else
1779 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1780 ws[0] = '\0'; wpos = 0; 1851 ws[0] = '\0'; wpos = 0;
1781 /* NEW_BIT(NEW_TEXT_BIT); */ 1852 /* NEW_BIT(NEW_TEXT_BIT); */
1782 if (bg) 1853 if (bg)
1783 g_free(bg); 1854 g_free(bg);
1784 bg = bgcolor; 1855 bg = bgcolor;
1787 } 1858 }
1788 break; 1859 break;
1789 case 45: /* A (opt) */ 1860 case 45: /* A (opt) */
1790 { 1861 {
1791 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); 1862 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF=");
1792 if (href) { 1863 if (href && (imhtml->format_functions & GTK_IMHTML_LINK)) {
1793 if (url) { 1864 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1794 gtk_imhtml_insert_link(imhtml, url, ws);
1795 g_free(url);
1796 } else
1797 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1798 ws[0] = '\0'; wpos = 0; 1865 ws[0] = '\0'; wpos = 0;
1799 url = href; 1866 gtk_imhtml_toggle_link(imhtml, href);
1800 } 1867 }
1801 } 1868 }
1802 break; 1869 break;
1803 case 46: /* IMG (opt) */ 1870 case 46: /* IMG (opt) */
1804 case 59: /* IMG */ 1871 case 59: /* IMG */
1805 { 1872 {
1873 #if 0
1874 /* disabling this for now, it's easy to add it back... */
1806 GdkPixbuf *img = NULL; 1875 GdkPixbuf *img = NULL;
1807 const gchar *filename = NULL; 1876 const gchar *filename = NULL;
1877
1878 if (!(imhtml->format_functions & GTK_IMHTML_IMAGE))
1879 break;
1808 1880
1809 if (images && images->data) { 1881 if (images && images->data) {
1810 img = images->data; 1882 img = images->data;
1811 images = images->next; 1883 images = images->next;
1812 filename = g_object_get_data(G_OBJECT(img), "filename"); 1884 filename = g_object_get_data(G_OBJECT(img), "filename");
1817 "gtkimhtml-missing-image"); 1889 "gtkimhtml-missing-image");
1818 } 1890 }
1819 1891
1820 scalable = gtk_imhtml_image_new(img, filename); 1892 scalable = gtk_imhtml_image_new(img, filename);
1821 /* NEW_BIT(NEW_SCALABLE_BIT); */ 1893 /* NEW_BIT(NEW_SCALABLE_BIT); */
1894 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
1895 scalable->add_to(scalable, imhtml, iter);
1896 scalable->scale(scalable, rect.width, rect.height);
1897 imhtml->scalables = g_list_append(imhtml->scalables, scalable);
1898
1822 g_object_unref(G_OBJECT(img)); 1899 g_object_unref(G_OBJECT(img));
1900 #endif
1823 } 1901 }
1824 case 47: /* P (opt) */ 1902 case 47: /* P (opt) */
1825 case 48: /* H3 (opt) */ 1903 case 48: /* H3 (opt) */
1826 case 49: /* HTML (opt) */ 1904 case 49: /* HTML (opt) */
1827 case 50: /* CITE */ 1905 case 50: /* CITE */
1848 if (!(color || family || size)) { 1926 if (!(color || family || size)) {
1849 g_free(style); 1927 g_free(style);
1850 break; 1928 break;
1851 } 1929 }
1852 1930
1853 if (url) 1931
1854 gtk_imhtml_insert_link(imhtml, url, ws); 1932 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1855 else
1856 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1857 ws[0] = '\0'; wpos = 0; 1933 ws[0] = '\0'; wpos = 0;
1858 /* NEW_BIT (NEW_TEXT_BIT); */ 1934 /* NEW_BIT (NEW_TEXT_BIT); */
1859 1935
1860 font = g_new0 (GtkIMHtmlFontDetail, 1); 1936 font = g_new0 (GtkIMHtmlFontDetail, 1);
1861 if (fonts) 1937 if (fonts)
1862 oldfont = fonts->data; 1938 oldfont = fonts->data;
1863 1939
1864 if (color && !(options & GTK_IMHTML_NO_COLOURS)) 1940 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR))
1865 font->fore = color; 1941 font->fore = color;
1866 else if (oldfont && oldfont->fore) 1942 else if (oldfont && oldfont->fore)
1867 font->fore = g_strdup(oldfont->fore); 1943 font->fore = g_strdup(oldfont->fore);
1868 1944
1869 if (oldfont && oldfont->back) 1945 if (oldfont && oldfont->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR))
1870 font->back = g_strdup(oldfont->back); 1946 font->back = g_strdup(oldfont->back);
1871 1947
1872 if (family && !(options & GTK_IMHTML_NO_FONTS)) 1948 if (family && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE))
1873 font->face = family; 1949 font->face = family;
1874 else if (oldfont && oldfont->face) 1950 else if (oldfont && oldfont->face)
1875 font->face = g_strdup(oldfont->face); 1951 font->face = g_strdup(oldfont->face);
1876 if (font->face && (atoi(font->face) > 100)) { 1952 if (font->face && (atoi(font->face) > 100)) {
1953 /* WTF is this? */
1877 g_free(font->face); 1954 g_free(font->face);
1878 font->face = g_strdup("100"); 1955 font->face = g_strdup("100");
1879 } 1956 }
1880 1957
1881 if (oldfont && oldfont->sml) 1958 if (oldfont && oldfont->sml)
1882 font->sml = g_strdup(oldfont->sml); 1959 font->sml = g_strdup(oldfont->sml);
1883 1960
1884 if (size && !(options & GTK_IMHTML_NO_SIZES)) { 1961 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_SHRINK|GTK_IMHTML_GROW))) {
1885 if (g_ascii_strcasecmp(size, "smaller") == 0) 1962 if (g_ascii_strcasecmp(size, "smaller") == 0)
1886 { 1963 {
1887 font->size = 2; 1964 font->size = 2;
1888 } 1965 }
1889 else if (g_ascii_strcasecmp(size, "larger") == 0) 1966 else if (g_ascii_strcasecmp(size, "larger") == 0)
1902 fonts = g_slist_prepend (fonts, font); 1979 fonts = g_slist_prepend (fonts, font);
1903 } 1980 }
1904 break; 1981 break;
1905 case 57: /* /SPAN */ 1982 case 57: /* /SPAN */
1906 /* Inline CSS Support - Douglas Thrift */ 1983 /* Inline CSS Support - Douglas Thrift */
1907 if (fonts) { 1984 if (fonts && !imhtml->wbfo) {
1908 GtkIMHtmlFontDetail *font = fonts->data; 1985 GtkIMHtmlFontDetail *font = fonts->data;
1909 if (url) 1986 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1910 gtk_imhtml_insert_link(imhtml, url, ws);
1911 else
1912 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1913 ws[0] = '\0'; wpos = 0; 1987 ws[0] = '\0'; wpos = 0;
1914 /* NEW_BIT (NEW_TEXT_BIT); */ 1988 /* NEW_BIT (NEW_TEXT_BIT); */
1915 fonts = g_slist_remove (fonts, font); 1989 fonts = g_slist_remove (fonts, font);
1916 if (font->face) 1990 if (font->face)
1917 g_free (font->face); 1991 g_free (font->face);
1927 case 60: /* SPAN */ 2001 case 60: /* SPAN */
1928 break; 2002 break;
1929 case 62: /* comment */ 2003 case 62: /* comment */
1930 /* NEW_BIT (NEW_TEXT_BIT); */ 2004 /* NEW_BIT (NEW_TEXT_BIT); */
1931 ws[wpos] = '\0'; 2005 ws[wpos] = '\0';
1932 if (url) 2006 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1933 gtk_imhtml_insert_link(imhtml, url, ws); 2007
1934 else
1935 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1936 if (imhtml->show_comments) 2008 if (imhtml->show_comments)
1937 wpos = g_snprintf (ws, len, "%s", tag); 2009 wpos = g_snprintf (ws, len, "%s", tag);
1938 /* NEW_BIT (NEW_COMMENT_BIT); */ 2010 /* NEW_BIT (NEW_COMMENT_BIT); */
1939 break; 2011 break;
1940 default: 2012 default:
1950 gchar *sml = NULL; 2022 gchar *sml = NULL;
1951 if (fonts) { 2023 if (fonts) {
1952 fd = fonts->data; 2024 fd = fonts->data;
1953 sml = fd->sml; 2025 sml = fd->sml;
1954 } 2026 }
1955 if (url) 2027 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1956 gtk_imhtml_insert_link(imhtml, url, ws);
1957 else {
1958 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1959 }
1960 wpos = g_snprintf (ws, smilelen + 1, "%s", c); 2028 wpos = g_snprintf (ws, smilelen + 1, "%s", c);
1961 2029
1962 gtk_imhtml_insert_smiley(imhtml, sml, ws); 2030 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, ws, iter);
1963
1964 ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
1965 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
1966 2031
1967 c += smilelen; 2032 c += smilelen;
1968 pos += smilelen; 2033 pos += smilelen;
1969 wpos = 0; 2034 wpos = 0;
1970 ws[0] = 0; 2035 ws[0] = 0;
1976 pos += tlen; 2041 pos += tlen;
1977 } else if (*c == '\n') { 2042 } else if (*c == '\n') {
1978 if (!(options & GTK_IMHTML_NO_NEWLINE)) { 2043 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
1979 ws[wpos] = '\n'; 2044 ws[wpos] = '\n';
1980 wpos++; 2045 wpos++;
1981 if (url) 2046 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
1982 gtk_imhtml_insert_link(imhtml, url, ws);
1983 else
1984 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1985 ws[0] = '\0'; 2047 ws[0] = '\0';
1986 wpos = 0; 2048 wpos = 0;
1987 /* NEW_BIT (NEW_TEXT_BIT); */ 2049 /* NEW_BIT (NEW_TEXT_BIT); */
1988 } 2050 }
1989 c++; 2051 c++;
1990 pos++; 2052 pos++;
1991 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ 2053 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){
1992 while(len_protocol--){ 2054 while(len_protocol--){
1993 /* Skip the next len_protocol characters, but make sure they're 2055 /* Skip the next len_protocol characters, but make sure they're
1994 copied into the ws array. 2056 copied into the ws array.
1995 */ 2057 */
1996 ws [wpos++] = *c++; 2058 ws [wpos++] = *c++;
1997 pos++; 2059 pos++;
1998 } 2060 }
2001 pos++; 2063 pos++;
2002 } else { 2064 } else {
2003 break; 2065 break;
2004 } 2066 }
2005 } 2067 }
2006 if (url) 2068 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);
2007 gtk_imhtml_insert_link(imhtml, url, ws);
2008 else
2009 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
2010 ws[0] = '\0'; wpos = 0; 2069 ws[0] = '\0'; wpos = 0;
2011 2070
2012 /* NEW_BIT(NEW_TEXT_BIT); */ 2071 /* NEW_BIT(NEW_TEXT_BIT); */
2013 if (url) {
2014 g_free (url);
2015 if (str)
2016 str = g_string_append (str, "</A>");
2017 }
2018 2072
2019 while (fonts) { 2073 while (fonts) {
2020 GtkIMHtmlFontDetail *font = fonts->data; 2074 GtkIMHtmlFontDetail *font = fonts->data;
2021 fonts = g_slist_remove (fonts, font); 2075 fonts = g_slist_remove (fonts, font);
2022 if (font->face) 2076 if (font->face)
2026 if (font->back) 2080 if (font->back)
2027 g_free (font->back); 2081 g_free (font->back);
2028 if (font->sml) 2082 if (font->sml)
2029 g_free (font->sml); 2083 g_free (font->sml);
2030 g_free (font); 2084 g_free (font);
2031 if (str) 2085 //if (str)
2032 str = g_string_append (str, "</FONT>"); 2086 // str = g_string_append (str, "</FONT>");
2033 } 2087 }
2034 2088 #if 0
2035 if (str) { 2089 if (str) {
2036 while (bold) { 2090 while (bold) {
2037 str = g_string_append (str, "</B>"); 2091 // str = g_string_append (str, "</B>");
2038 bold--; 2092 bold--;
2039 } 2093 }
2040 while (italics) { 2094 while (italics) {
2041 str = g_string_append (str, "</I>"); 2095 // str = g_string_append (str, "</I>");
2042 italics--; 2096 italics--;
2043 } 2097 }
2044 while (underline) { 2098 while (underline) {
2045 str = g_string_append (str, "</U>"); 2099 //str = g_string_append (str, "</U>");
2046 underline--; 2100 underline--;
2047 } 2101 }
2048 while (strike) { 2102 while (strike) {
2049 str = g_string_append (str, "</S>"); 2103 //str = g_string_append (str, "</S>");
2050 strike--; 2104 strike--;
2051 } 2105 }
2052 while (sub) { 2106 while (sub) {
2053 str = g_string_append (str, "</SUB>"); 2107 //str = g_string_append (str, "</SUB>");
2054 sub--; 2108 sub--;
2055 } 2109 }
2056 while (sup) { 2110 while (sup) {
2057 str = g_string_append (str, "</SUP>"); 2111 //str = g_string_append (str, "</SUP>");
2058 sup--; 2112 sup--;
2059 } 2113 }
2060 while (title) { 2114 while (title) {
2061 str = g_string_append (str, "</TITLE>"); 2115 //str = g_string_append (str, "</TITLE>");
2062 title--; 2116 title--;
2063 } 2117 }
2064 while (pre) { 2118 while (pre) {
2065 str = g_string_append (str, "</PRE>"); 2119 //str = g_string_append (str, "</PRE>");
2066 pre--; 2120 pre--;
2067 } 2121 }
2068 } 2122 }
2123 #endif
2069 g_free (ws); 2124 g_free (ws);
2070 if(bg) 2125 if(bg)
2071 g_free(bg); 2126 g_free(bg);
2072 /* this shouldn't be necessary if we want to be able to continue 2127
2073 * using the format if it was unclosed. But seeing as removing this 2128 if (!imhtml->wbfo)
2074 * line does not help the ctrl-up/down from enabling open tags, I'm 2129 gtk_imhtml_close_tags(imhtml);
2075 * leaving it up to sean, or unless I find some time to look into it
2076 * more -Gary */
2077 gtk_imhtml_close_tags(imhtml);
2078 if (!(options & GTK_IMHTML_NO_SCROLL))
2079 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark,
2080 0, TRUE, 0.0, 1.0);
2081 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark);
2082 gtk_text_buffer_move_mark (imhtml->text_buffer,
2083 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"),
2084 &iter);
2085 2130
2086 object = g_object_ref(G_OBJECT(imhtml)); 2131 object = g_object_ref(G_OBJECT(imhtml));
2087 g_signal_emit(object, signals[UPDATE_FORMAT], 0); 2132 g_signal_emit(object, signals[UPDATE_FORMAT], 0);
2088 g_object_unref(object); 2133 g_object_unref(object);
2089 2134
2090 return str;
2091 } 2135 }
2092 2136
2093 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) 2137 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml)
2094 { 2138 {
2095 g_hash_table_destroy(imhtml->smiley_data); 2139 g_hash_table_destroy(imhtml->smiley_data);
2137 2181
2138 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); 2182 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
2139 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); 2183 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
2140 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); 2184 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end);
2141 2185
2142 for(del = imhtml->format_spans; del; del = del->next) {
2143 GtkIMHtmlFormatSpan *span = del->data;
2144 if (span->start_tag)
2145 g_free(span->start_tag);
2146 if (span->end_tag)
2147 g_free(span->end_tag);
2148 g_free(span);
2149 }
2150 g_list_free(imhtml->format_spans);
2151 imhtml->format_spans = NULL;
2152
2153 for(del = imhtml->scalables; del; del = del->next) { 2186 for(del = imhtml->scalables; del; del = del->next) {
2154 GtkIMHtmlScalable *scale = del->data; 2187 GtkIMHtmlScalable *scale = del->data;
2155 scale->free(scale); 2188 scale->free(scale);
2156 } 2189 }
2157 g_list_free(imhtml->scalables); 2190 g_list_free(imhtml->scalables);
2158 imhtml->scalables = NULL; 2191 imhtml->scalables = NULL;
2159 2192
2160 imhtml->edit.bold = NULL; 2193 imhtml->edit.bold = FALSE;
2161 imhtml->edit.italic = NULL; 2194 imhtml->edit.italic = FALSE;
2162 imhtml->edit.underline = NULL; 2195 imhtml->edit.underline = FALSE;
2196
2197 if (imhtml->edit.fontface)
2198 g_free(imhtml->edit.fontface);
2163 imhtml->edit.fontface = NULL; 2199 imhtml->edit.fontface = NULL;
2200
2201 if (imhtml->edit.forecolor)
2202 g_free(imhtml->edit.forecolor);
2164 imhtml->edit.forecolor = NULL; 2203 imhtml->edit.forecolor = NULL;
2204
2205 if (imhtml->edit.backcolor)
2206 g_free(imhtml->edit.backcolor);
2165 imhtml->edit.backcolor = NULL; 2207 imhtml->edit.backcolor = NULL;
2166 imhtml->edit.sizespan = NULL; 2208
2167 imhtml->edit.fontsize = 3; 2209 imhtml->edit.fontsize = 0;
2168 2210
2169 g_signal_emit(object, signals[CLEAR_FORMAT], 0); 2211 g_signal_emit(object, signals[CLEAR_FORMAT], 0);
2170 g_object_unref(object); 2212 g_object_unref(object);
2171 } 2213 }
2172 2214
2488 if (imhtml->search_string) 2530 if (imhtml->search_string)
2489 g_free(imhtml->search_string); 2531 g_free(imhtml->search_string);
2490 imhtml->search_string = NULL; 2532 imhtml->search_string = NULL;
2491 } 2533 }
2492 2534
2535 static GtkTextTag *find_font_forecolor_tag(GtkIMHtml *imhtml, gchar *color)
2536 {
2537 gchar str[18];
2538 GtkTextTag *tag;
2539
2540 g_snprintf(str, sizeof(str), "FORECOLOR %s", color);
2541
2542 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str);
2543 if (!tag)
2544 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", color, NULL);
2545
2546 return tag;
2547 }
2548
2549 static GtkTextTag *find_font_backcolor_tag(GtkIMHtml *imhtml, gchar *color)
2550 {
2551 gchar str[18];
2552 GtkTextTag *tag;
2553
2554 g_snprintf(str, sizeof(str), "BACKCOLOR %s", color);
2555
2556 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str);
2557 if (!tag)
2558 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "background", color, NULL);
2559
2560 return tag;
2561 }
2562
2563 static GtkTextTag *find_font_face_tag(GtkIMHtml *imhtml, gchar *face)
2564 {
2565 gchar str[256];
2566 GtkTextTag *tag;
2567
2568 g_snprintf(str, sizeof(str), "FONT FACE %s", face);
2569 str[255] = '\0';
2570
2571 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str);
2572 if (!tag)
2573 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "family", face, NULL);
2574
2575 return tag;
2576 }
2577
2578 static GtkTextTag *find_font_size_tag(GtkIMHtml *imhtml, int size)
2579 {
2580 gchar str[24];
2581 GtkTextTag *tag;
2582
2583 g_snprintf(str, sizeof(str), "FONT SIZE %d", size);
2584 str[23] = '\0';
2585
2586 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str);
2587 if (!tag) {
2588 /* For reasons I don't understand, setting "scale" here scaled based on some default
2589 * size other than my theme's default size. Our size 4 was actually smaller than
2590 * our size 3 for me. So this works around that oddity.
2591 */
2592 GtkTextAttributes *attr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(imhtml));
2593 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "size",
2594 (gint) (pango_font_description_get_size(attr->font) *
2595 (double) _point_sizes[size-1]), NULL);
2596 gtk_text_attributes_unref(attr);
2597 }
2598
2599 return tag;
2600 }
2601
2602 static void remove_tag_by_prefix(GtkIMHtml *imhtml, const GtkTextIter *i, const GtkTextIter *e,
2603 const char *prefix, guint len, gboolean homo)
2604 {
2605 GSList *tags, *l;
2606 GtkTextIter iter;
2607
2608 tags = gtk_text_iter_get_tags(i);
2609
2610 for (l = tags; l; l = l->next) {
2611 GtkTextTag *tag = l->data;
2612
2613 if (tag->name && !strncmp(tag->name, prefix, len))
2614 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, i, e);
2615 }
2616
2617 g_slist_free(tags);
2618
2619 if (homo)
2620 return;
2621
2622 iter = *i;
2623
2624 while (gtk_text_iter_forward_char(&iter) && !gtk_text_iter_equal(&iter, e)) {
2625 if (gtk_text_iter_begins_tag(&iter, NULL)) {
2626 tags = gtk_text_iter_get_toggled_tags(&iter, TRUE);
2627
2628 for (l = tags; l; l = l->next) {
2629 GtkTextTag *tag = l->data;
2630
2631 if (tag->name && !strncmp(tag->name, prefix, len))
2632 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e);
2633 }
2634
2635 g_slist_free(tags);
2636 }
2637 }
2638 }
2639
2640 static void remove_font_size(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo)
2641 {
2642 remove_tag_by_prefix(imhtml, i, e, "FONT SIZE ", 10, homo);
2643 }
2644
2645 static void remove_font_face(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo)
2646 {
2647 remove_tag_by_prefix(imhtml, i, e, "FONT FACE ", 10, homo);
2648 }
2649
2650 static void remove_font_forecolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo)
2651 {
2652 remove_tag_by_prefix(imhtml, i, e, "FORECOLOR ", 10, homo);
2653 }
2654
2655 static void remove_font_backcolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo)
2656 {
2657 remove_tag_by_prefix(imhtml, i, e, "BACKCOLOR ", 10, homo);
2658 }
2659
2660 static void remove_font_link(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo)
2661 {
2662 remove_tag_by_prefix(imhtml, i, e, "LINK ", 5, homo);
2663 }
2664
2493 /* Editable stuff */ 2665 /* Editable stuff */
2494 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) 2666 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml)
2495 { 2667 {
2496 GtkIMHtmlFormatSpan *span = NULL; 2668 imhtml->insert_offset = gtk_text_iter_get_offset(iter);
2497 GtkTextIter end; 2669 }
2498 2670
2499 gtk_text_iter_forward_chars(iter, len); 2671 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *end, gchar *text, gint len, GtkIMHtml *imhtml)
2500 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); 2672 {
2501 gtk_text_iter_forward_char(&end); 2673 GtkTextIter start;
2502 2674
2503 if (!gtk_text_iter_equal(&end, iter)) 2675 if (!len)
2504 return; 2676 return;
2505 2677
2506 2678 start = *end;
2507 if ((span = imhtml->edit.bold)) { 2679 gtk_text_iter_set_offset(&start, imhtml->insert_offset);
2508 GtkTextIter bold; 2680
2509 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &bold, span->start); 2681 if (imhtml->edit.bold)
2510 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &bold, iter); 2682 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, end);
2511 } 2683 else
2512 2684 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, end);
2513 if ((span = imhtml->edit.italic)) { 2685
2514 GtkTextIter italic; 2686 if (imhtml->edit.italic)
2515 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &italic, span->start); 2687 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end);
2516 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &italic, 2688 else
2517 iter); 2689 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end);
2518 } 2690
2519 2691 if (imhtml->edit.underline)
2520 if ((span = imhtml->edit.underline)) { 2692 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end);
2521 GtkTextIter underline; 2693 else
2522 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &underline, span->start); 2694 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end);
2523 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &underline, 2695
2524 iter); 2696 if (imhtml->edit.forecolor) {
2525 } 2697 remove_font_forecolor(imhtml, &start, end, TRUE);
2526 2698 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2527 if ((span = imhtml->edit.forecolor)) { 2699 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor),
2528 GtkTextIter fore; 2700 &start, end);
2529 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &fore, span->start); 2701 }
2530 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &fore, iter); 2702
2531 } 2703 if (imhtml->edit.backcolor) {
2532 2704 remove_font_backcolor(imhtml, &start, end, TRUE);
2533 if ((span = imhtml->edit.backcolor)) { 2705 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2534 GtkTextIter back; 2706 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor),
2535 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &back, span->start); 2707 &start, end);
2536 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &back, iter); 2708 }
2537 } 2709
2538 2710 if (imhtml->edit.fontface) {
2539 if ((span = imhtml->edit.fontface)) { 2711 remove_font_face(imhtml, &start, end, TRUE);
2540 GtkTextIter face; 2712 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2541 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &face, span->start); 2713 find_font_face_tag(imhtml, imhtml->edit.fontface),
2542 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &face, iter); 2714 &start, end);
2543 } 2715 }
2544 2716
2545 if ((span = imhtml->edit.sizespan)) { 2717 if (imhtml->edit.fontsize) {
2546 GtkTextIter size; 2718 remove_font_size(imhtml, &start, end, TRUE);
2547 /* We create the tags here so that one can grow font or shrink font several times 2719 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2548 * in a row without creating unnecessary tags */ 2720 find_font_size_tag(imhtml, imhtml->edit.fontsize),
2549 if (span->tag == NULL) { 2721 &start, end);
2550 span->tag = gtk_text_buffer_create_tag 2722 }
2551 (imhtml->text_buffer, NULL, "scale", (double)_point_sizes [imhtml->edit.fontsize-1], NULL); 2723
2552 span->start_tag = g_strdup_printf("<font size=\"%d\">", imhtml->edit.fontsize); 2724 if (imhtml->edit.link) {
2553 span->end_tag = g_strdup("</font>"); 2725 remove_font_link(imhtml, &start, end, TRUE);
2554 } 2726 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2555 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &size, span->start); 2727 imhtml->edit.link,
2556 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &size, iter); 2728 &start, end);
2557 } 2729 }
2730
2558 } 2731 }
2559 2732
2560 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) 2733 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable)
2561 { 2734 {
2562 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); 2735 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable);
2564 * We need a visible caret for accessibility, so mouseless 2737 * We need a visible caret for accessibility, so mouseless
2565 * people can highlight stuff. 2738 * people can highlight stuff.
2566 */ 2739 */
2567 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ 2740 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */
2568 imhtml->editable = editable; 2741 imhtml->editable = editable;
2569 imhtml->format_functions = !editable ? 0 : -1; 2742 imhtml->format_functions = GTK_IMHTML_ALL;
2743
2744 if (editable)
2745 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set",
2746 G_CALLBACK(mark_set_cb), imhtml);
2747 }
2748
2749 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo)
2750 {
2751 g_return_if_fail(imhtml != NULL);
2752
2753 imhtml->wbfo = wbfo;
2570 } 2754 }
2571 2755
2572 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) 2756 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons)
2573 { 2757 {
2574 GObject *object = g_object_ref(G_OBJECT(imhtml)); 2758 GObject *object = g_object_ref(G_OBJECT(imhtml));
2759 imhtml->format_functions = buttons;
2575 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); 2760 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons);
2576 imhtml->format_functions = buttons;
2577 g_object_unref(object); 2761 g_object_unref(object);
2578 } 2762 }
2579 2763
2580 static gboolean
2581 gtk_imhtml_has_open_tags(GtkIMHtml *imhtml) {
2582 if(imhtml->edit.bold && imhtml->edit.bold->end == NULL)
2583 return TRUE;
2584
2585 if(imhtml->edit.italic && imhtml->edit.italic->end == NULL)
2586 return TRUE;
2587
2588 if(imhtml->edit.underline && imhtml->edit.underline->end == NULL)
2589 return TRUE;
2590
2591 if(imhtml->edit.forecolor && imhtml->edit.forecolor->end == NULL)
2592 return TRUE;
2593
2594 if(imhtml->edit.backcolor && imhtml->edit.backcolor->end == NULL)
2595 return TRUE;
2596
2597 if(imhtml->edit.fontface && imhtml->edit.fontface->end == NULL)
2598 return TRUE;
2599
2600 if(imhtml->edit.sizespan && imhtml->edit.sizespan->end == NULL)
2601 return TRUE;
2602
2603 return FALSE;
2604 }
2605 2764
2606 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, 2765 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold,
2607 gboolean *italic, gboolean *underline) 2766 gboolean *italic, gboolean *underline)
2608 { 2767 {
2609 GtkTextMark *ins_mark; 2768 if (imhtml->edit.bold)
2610 GtkTextIter ins_iter; 2769 (*bold) = TRUE;
2611 GSList *tags; 2770 if (imhtml->edit.italic)
2612 2771 (*italic) = TRUE;
2613 ins_mark = gtk_text_buffer_get_insert(imhtml->text_buffer); 2772 if (imhtml->edit.underline)
2614 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins_iter, ins_mark); 2773 (*underline) = TRUE;
2615
2616 if(gtk_imhtml_has_open_tags(imhtml)) {
2617 GtkTextIter end_iter;
2618 gint position, length;
2619
2620 position = gtk_text_iter_get_offset(&ins_iter);
2621
2622 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end_iter);
2623 length = gtk_text_iter_get_offset(&end_iter);
2624
2625 if(position == length)
2626 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins_iter,
2627 length - 1);
2628 }
2629
2630 for(tags = gtk_text_iter_get_tags(&ins_iter);
2631 tags != NULL; tags = tags->next)
2632 {
2633 GtkTextTag *tag = GTK_TEXT_TAG(tags->data);
2634 if(tag->name) {
2635 if(g_ascii_strcasecmp(tag->name, "BOLD") == 0)
2636 (*bold) = TRUE;
2637 if(g_ascii_strcasecmp(tag->name, "ITALICS") == 0)
2638 (*italic) = TRUE;
2639 if(g_ascii_strcasecmp(tag->name, "UNDERLINE") == 0)
2640 (*underline) = TRUE;
2641 }
2642 }
2643 } 2774 }
2644 2775
2645 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) 2776 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml)
2646 { 2777 {
2647 return imhtml->editable; 2778 return imhtml->editable;
2648 } 2779 }
2649 2780
2781 /*
2782 * I had this crazy idea about changing the text cursor color to reflex the foreground color
2783 * of the text about to be entered. This is the place you'd do it, along with the place where
2784 * we actually set a new foreground color.
2785 * I may not do this, because people will bitch about Gaim overriding their gtk theme's cursor
2786 * colors.
2787 *
2788 * Just in case I do do this, I asked about what to set the secondary text cursor to.
2789 *
2790 (12:45:27) ?? ???: secondary_cursor_color = (rgb(background) + rgb(primary_cursor_color) ) / 2 *
2791 (12:45:55) ?? ???: understand? *
2792 * (12:46:14) Tim: yeah. i didn't know there was an exact formula
2793 (12:46:56) ?? ???: u might need to exactract separate each color from RGB *
2794 */
2795
2796 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark,
2797 GtkIMHtml *imhtml)
2798 {
2799 GSList *tags, *l;
2800 GtkTextIter iter;
2801
2802 if (mark != gtk_text_buffer_get_insert(buffer))
2803 return;
2804
2805 if (!gtk_text_buffer_get_char_count(buffer))
2806 return;
2807
2808 imhtml->edit.bold = imhtml->edit.italic = imhtml->edit.underline = FALSE;
2809 if (imhtml->edit.forecolor)
2810 g_free(imhtml->edit.forecolor);
2811 imhtml->edit.forecolor = NULL;
2812 if (imhtml->edit.backcolor)
2813 g_free(imhtml->edit.backcolor);
2814 imhtml->edit.backcolor = NULL;
2815 if (imhtml->edit.fontface)
2816 g_free(imhtml->edit.fontface);
2817 imhtml->edit.fontface = NULL;
2818 imhtml->edit.fontsize = 0;
2819 imhtml->edit.link = NULL;
2820
2821 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark);
2822
2823
2824 if (gtk_text_iter_is_end(&iter))
2825 tags = gtk_text_iter_get_toggled_tags(&iter, FALSE);
2826 else
2827 tags = gtk_text_iter_get_tags(&iter);
2828
2829 for (l = tags; l != NULL; l = l->next) {
2830 GtkTextTag *tag = GTK_TEXT_TAG(l->data);
2831
2832 if (tag->name) {
2833 if (strcmp(tag->name, "BOLD") == 0)
2834 imhtml->edit.bold = TRUE;
2835 if (strcmp(tag->name, "ITALICS") == 0)
2836 imhtml->edit.italic = TRUE;
2837 if (strcmp(tag->name, "UNDERLINE") == 0)
2838 imhtml->edit.underline = TRUE;
2839 if (strncmp(tag->name, "FORECOLOR ", 10) == 0)
2840 imhtml->edit.forecolor = g_strdup(&(tag->name)[10]);
2841 if (strncmp(tag->name, "BACKCOLOR ", 10) == 0)
2842 imhtml->edit.backcolor = g_strdup(&(tag->name)[10]);
2843 if (strncmp(tag->name, "FONT FACE ", 10) == 0)
2844 imhtml->edit.fontface = g_strdup(&(tag->name)[10]);
2845 if (strncmp(tag->name, "FONT SIZE ", 10) == 0)
2846 imhtml->edit.fontsize = strtol(&(tag->name)[10], NULL, 10);
2847 if (strncmp(tag->name, "LINK ", 5) == 0)
2848 imhtml->edit.link = tag;
2849 }
2850 }
2851
2852 g_slist_free(tags);
2853 }
2854
2650 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) 2855 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml)
2651 { 2856 {
2652 GtkIMHtmlFormatSpan *span;
2653 GObject *object; 2857 GObject *object;
2654 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 2858 GtkTextIter start, end;
2655 GtkTextIter iter; 2859
2656 2860 imhtml->edit.bold = !imhtml->edit.bold;
2657 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 2861
2658 2862 if (imhtml->wbfo) {
2659 if (!imhtml->edit.bold) { 2863 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
2660 span = g_new0(GtkIMHtmlFormatSpan, 1); 2864 if (imhtml->edit.bold)
2661 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2865 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end);
2662 span->start_tag = g_strdup("<b>"); 2866 else
2663 span->end = NULL; 2867 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end);
2664 span->end_tag = g_strdup("</b>"); 2868 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
2665 span->buffer = imhtml->text_buffer; 2869 if (imhtml->edit.bold)
2666 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "BOLD"); 2870 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end);
2667 imhtml->edit.bold = span; 2871 else
2668 imhtml->format_spans = g_list_append(imhtml->format_spans, span); 2872 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end);
2669 } else { 2873
2670 GtkTextIter start; 2874 }
2671 span = imhtml->edit.bold;
2672 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2673 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, span->start);
2674 if (gtk_text_iter_equal(&start, &iter)) {
2675 /* Format turned off before any text was entered, so remove the tag */
2676 imhtml->format_spans = g_list_remove(imhtml->format_spans, span);
2677 if (span->start_tag)
2678 g_free(span->start_tag);
2679 if (span->end_tag)
2680 g_free(span->end_tag);
2681 g_free(span);
2682 }
2683 imhtml->edit.bold = NULL;
2684 }
2685
2686 object = g_object_ref(G_OBJECT(imhtml)); 2875 object = g_object_ref(G_OBJECT(imhtml));
2687 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BOLD); 2876 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BOLD);
2688 g_object_unref(object); 2877 g_object_unref(object);
2689 2878
2690 return (imhtml->edit.bold != NULL); 2879 return (imhtml->edit.bold != FALSE);
2691 } 2880 }
2692 2881
2693 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) 2882 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml)
2694 { 2883 {
2695 GtkIMHtmlFormatSpan *span;
2696 GObject *object; 2884 GObject *object;
2697 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 2885 GtkTextIter start, end;
2698 GtkTextIter iter; 2886
2699 2887 imhtml->edit.italic = !imhtml->edit.italic;
2700 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 2888
2701 2889 if (imhtml->wbfo) {
2702 if (!imhtml->edit.italic) { 2890 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
2703 span = g_new0(GtkIMHtmlFormatSpan, 1); 2891 if (imhtml->edit.italic)
2704 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2892 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end);
2705 span->start_tag = g_strdup("<i>"); 2893 else
2706 span->end = NULL; 2894 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end);
2707 span->end_tag = g_strdup("</i>"); 2895 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
2708 span->buffer = imhtml->text_buffer; 2896 if (imhtml->edit.italic)
2709 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "ITALIC"); 2897 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end);
2710 imhtml->edit.italic = span; 2898 else
2711 imhtml->format_spans = g_list_append(imhtml->format_spans, span); 2899 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end);
2712 } else { 2900 }
2713 GtkTextIter start;
2714 span = imhtml->edit.italic;
2715 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2716 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, span->start);
2717 if (gtk_text_iter_equal(&start, &iter)) { /* Format turned off before any text was entered, so remove the tag */
2718 imhtml->format_spans = g_list_remove(imhtml->format_spans, span);
2719 if (span->start_tag)
2720 g_free(span->start_tag);
2721 if (span->end_tag)
2722 g_free(span->end_tag);
2723 g_free(span);
2724 }
2725 imhtml->edit.italic = NULL;
2726 }
2727
2728 object = g_object_ref(G_OBJECT(imhtml)); 2901 object = g_object_ref(G_OBJECT(imhtml));
2729 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_ITALIC); 2902 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_ITALIC);
2730 g_object_unref(object); 2903 g_object_unref(object);
2731 2904
2732 return imhtml->edit.italic != NULL; 2905 return imhtml->edit.italic != FALSE;
2733 } 2906 }
2734 2907
2735 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) 2908 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml)
2736 { 2909 {
2737 GtkIMHtmlFormatSpan *span;
2738 GObject *object; 2910 GObject *object;
2739 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 2911 GtkTextIter start, end;
2740 GtkTextIter iter; 2912
2741 2913 imhtml->edit.underline = !imhtml->edit.underline;
2742 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 2914
2743 2915 if (imhtml->wbfo) {
2744 if (!imhtml->edit.underline) { 2916 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
2745 span = g_new0(GtkIMHtmlFormatSpan, 1); 2917 if (imhtml->edit.underline)
2746 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2918 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end);
2747 span->start_tag = g_strdup("<u>"); 2919 else
2748 span->end = NULL; 2920 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end);
2749 span->end_tag = g_strdup("</u>"); 2921 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
2750 span->buffer = imhtml->text_buffer; 2922 if (imhtml->edit.underline)
2751 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "UNDERLINE"); 2923 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end);
2752 imhtml->edit.underline = span; 2924 else
2753 imhtml->format_spans = g_list_append(imhtml->format_spans, span); 2925 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end);
2754 } else { 2926 }
2755 GtkTextIter start;
2756 span = imhtml->edit.underline;
2757 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2758 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, span->start);
2759 if (gtk_text_iter_equal(&start, &iter)) { /* Format turned off before any text was entered, so remove the tag */
2760 imhtml->format_spans = g_list_remove(imhtml->format_spans, span);
2761 if (span->start_tag)
2762 g_free(span->start_tag);
2763 if (span->end_tag)
2764 g_free(span->end_tag);
2765 g_free(span);
2766 }
2767 imhtml->edit.underline = NULL;
2768 }
2769
2770 object = g_object_ref(G_OBJECT(imhtml)); 2927 object = g_object_ref(G_OBJECT(imhtml));
2771 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_UNDERLINE); 2928 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_UNDERLINE);
2772 g_object_unref(object); 2929 g_object_unref(object);
2773 2930
2774 return imhtml->edit.underline != NULL; 2931 return imhtml->edit.underline != FALSE;
2775 } 2932 }
2776 2933
2777 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) 2934 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size)
2778 { 2935 {
2779 GtkIMHtmlFormatSpan *span; 2936 GtkTextIter start, end;
2780 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2781 GtkTextIter iter;
2782 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2783 2937
2784 imhtml->edit.fontsize = size; 2938 imhtml->edit.fontsize = size;
2785 2939
2786 if (imhtml->edit.sizespan) { 2940
2787 GtkTextIter iter2; 2941 if (imhtml->wbfo) {
2788 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); 2942 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
2789 if (gtk_text_iter_equal(&iter2, &iter)) 2943 remove_font_size(imhtml, &start, &end, TRUE);
2790 return; 2944 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2791 span = imhtml->edit.sizespan; 2945 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end);
2792 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2946 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
2793 } 2947 remove_font_size(imhtml, &start, &end, FALSE);
2794 if (size != -1) { 2948 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2795 span = g_malloc0(sizeof(GtkIMHtmlFormatSpan)); 2949 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end);
2796 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2950 }
2797 span->end = NULL; 2951
2798 span->buffer = imhtml->text_buffer;
2799 span->tag = NULL;
2800 imhtml->edit.sizespan = span;
2801 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2802 }
2803 } 2952 }
2804 2953
2805 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) 2954 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml)
2806 { 2955 {
2807 GtkIMHtmlFormatSpan *span; 2956 GtkTextIter start, end;
2808 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 2957
2809 GtkTextIter iter;
2810 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2811 if (imhtml->edit.fontsize == 1) 2958 if (imhtml->edit.fontsize == 1)
2812 return; 2959 return;
2813 2960
2814 imhtml->edit.fontsize--; 2961 if (!imhtml->edit.fontsize)
2815 2962 imhtml->edit.fontsize = 2;
2816 if (imhtml->edit.sizespan) { 2963 else
2817 GtkTextIter iter2; 2964 imhtml->edit.fontsize--;
2818 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); 2965
2819 if (gtk_text_iter_equal(&iter2, &iter)) 2966 if (imhtml->wbfo) {
2820 return; 2967 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
2821 span = imhtml->edit.sizespan; 2968 remove_font_size(imhtml, &start, &end, TRUE);
2822 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2969 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2823 } 2970 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end);
2824 2971 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
2825 span = g_malloc0(sizeof(GtkIMHtmlFormatSpan)); 2972 remove_font_size(imhtml, &start, &end, FALSE);
2826 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2973 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2827 span->end = NULL; 2974 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end);
2828 span->buffer = imhtml->text_buffer; 2975 }
2829 span->tag = NULL;
2830 imhtml->edit.sizespan = span;
2831 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2832 } 2976 }
2833 2977
2834 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) 2978 void gtk_imhtml_font_grow(GtkIMHtml *imhtml)
2835 { 2979 {
2836 GtkIMHtmlFormatSpan *span; 2980 GtkTextIter start, end;
2837 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 2981
2838 GtkTextIter iter;
2839 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2840 if (imhtml->edit.fontsize == MAX_FONT_SIZE) 2982 if (imhtml->edit.fontsize == MAX_FONT_SIZE)
2841 return; 2983 return;
2842 2984
2843 imhtml->edit.fontsize++; 2985 if (!imhtml->edit.fontsize)
2844 if (imhtml->edit.sizespan) { 2986 imhtml->edit.fontsize = 4;
2845 GtkTextIter iter2; 2987 else
2846 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); 2988 imhtml->edit.fontsize++;
2847 if (gtk_text_iter_equal(&iter2, &iter)) 2989
2848 return; 2990 if (imhtml->wbfo) {
2849 span = imhtml->edit.sizespan; 2991 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
2850 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2992 remove_font_size(imhtml, &start, &end, TRUE);
2851 } 2993 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2852 2994 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end);
2853 span = g_malloc0(sizeof(GtkIMHtmlFormatSpan)); 2995 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
2854 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 2996 remove_font_size(imhtml, &start, &end, FALSE);
2855 span->end = NULL; 2997 gtk_text_buffer_apply_tag(imhtml->text_buffer,
2856 span->tag = NULL; 2998 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end);
2857 span->buffer = imhtml->text_buffer; 2999 }
2858 imhtml->edit.sizespan = span;
2859 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2860 } 3000 }
2861 3001
2862 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) 3002 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color)
2863 { 3003 {
2864 GtkIMHtmlFormatSpan *span; 3004 GtkTextIter start, end;
2865 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 3005
3006 if (imhtml->edit.forecolor != NULL)
3007 g_free(imhtml->edit.forecolor);
3008
3009 if (color) {
3010 imhtml->edit.forecolor = g_strdup(color);
3011 if (imhtml->wbfo) {
3012 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
3013 remove_font_forecolor(imhtml, &start, &end, TRUE);
3014 gtk_text_buffer_apply_tag(imhtml->text_buffer,
3015 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), &start, &end);
3016 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
3017 remove_font_forecolor(imhtml, &start, &end, FALSE);
3018 gtk_text_buffer_apply_tag(imhtml->text_buffer,
3019 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor),
3020 &start, &end);
3021 }
3022 } else {
3023 imhtml->edit.forecolor = NULL;
3024 }
3025
3026 return imhtml->edit.forecolor != NULL;
3027 }
3028
3029 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color)
3030 {
3031 GtkTextIter start, end;
3032
3033 if (imhtml->edit.backcolor != NULL)
3034 g_free(imhtml->edit.backcolor);
3035
3036 if (color) {
3037 imhtml->edit.backcolor = g_strdup(color);
3038
3039 if (imhtml->wbfo) {
3040 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
3041 remove_font_backcolor(imhtml, &start, &end, TRUE);
3042 gtk_text_buffer_apply_tag(imhtml->text_buffer,
3043 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), &start, &end);
3044 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
3045 remove_font_backcolor(imhtml, &start, &end, FALSE);
3046 gtk_text_buffer_apply_tag(imhtml->text_buffer,
3047 find_font_backcolor_tag(imhtml,
3048 imhtml->edit.backcolor), &start, &end);
3049 }
3050 } else {
3051 imhtml->edit.backcolor = NULL;
3052 }
3053
3054 return imhtml->edit.backcolor != NULL;
3055 }
3056
3057 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face)
3058 {
3059 GtkTextIter start, end;
3060
3061 if (imhtml->edit.fontface != NULL)
3062 g_free(imhtml->edit.fontface);
3063
3064 if (face) {
3065 imhtml->edit.fontface = g_strdup(face);
3066
3067 if (imhtml->wbfo) {
3068 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end);
3069 remove_font_face(imhtml, &start, &end, TRUE);
3070 gtk_text_buffer_apply_tag(imhtml->text_buffer,
3071 find_font_face_tag(imhtml, imhtml->edit.fontface), &start, &end);
3072 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
3073 remove_font_face(imhtml, &start, &end, FALSE);
3074 gtk_text_buffer_apply_tag(imhtml->text_buffer,
3075 find_font_face_tag(imhtml, imhtml->edit.fontface),
3076 &start, &end);
3077 }
3078 } else {
3079 imhtml->edit.fontface = NULL;
3080 }
3081
3082 return imhtml->edit.fontface != NULL;
3083 }
3084
3085 void gtk_imhtml_toggle_link(GtkIMHtml *imhtml, const char *url)
3086 {
3087 GtkTextIter start, end;
3088 GtkTextTag *linktag;
3089 static guint linkno = 0;
3090 gchar str[48];
3091
3092 imhtml->edit.link = NULL;
3093
3094
3095
3096 if (url) {
3097 g_snprintf(str, sizeof(str), "LINK %d", linkno++);
3098 str[47] = '\0';
3099
3100 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL);
3101 g_object_set_data_full(G_OBJECT(linktag), "link_url", g_strdup(url), g_free);
3102 g_signal_connect(G_OBJECT(linktag), "event", G_CALLBACK(tag_event), NULL);
3103
3104 if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) {
3105 remove_font_link(imhtml, &start, &end, FALSE);
3106 gtk_text_buffer_apply_tag(imhtml->text_buffer, linktag, &start, &end);
3107 }
3108 }
3109 }
3110
3111 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text)
3112 {
2866 GtkTextIter iter; 3113 GtkTextIter iter;
2867 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 3114
2868 if (color) { 3115 gtk_imhtml_toggle_link(imhtml, url);
2869 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); 3116 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark);
2870 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 3117 gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1);
2871 span->start_tag = g_strdup_printf("<font color=\"%s\">", color); 3118 gtk_imhtml_toggle_link(imhtml, NULL);
2872 span->end = NULL; 3119 }
2873 span->end_tag = g_strdup("</font>"); 3120
2874 span->buffer = imhtml->text_buffer; 3121 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley)
2875 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", color, NULL); 3122 {
2876 imhtml->edit.forecolor = span; 3123 GtkTextMark *mark;
2877 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2878 } else {
2879 span = imhtml->edit.forecolor;
2880 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2881 imhtml->edit.forecolor = NULL;
2882 }
2883
2884
2885 return imhtml->edit.forecolor != NULL;
2886 }
2887
2888 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color)
2889 {
2890 GtkIMHtmlFormatSpan *span;
2891 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2892 GtkTextIter iter; 3124 GtkTextIter iter;
2893 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 3125
2894 if (color) { 3126 mark = gtk_text_buffer_get_insert(imhtml->text_buffer);
2895 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2896 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2897 span->start_tag = g_strdup_printf("<font back=\"%s\">", color);
2898 span->end = NULL;
2899 span->end_tag = g_strdup("</font>");
2900 span->buffer = imhtml->text_buffer;
2901 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", color, NULL);
2902 imhtml->edit.backcolor = span;
2903 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2904 } else {
2905 span = imhtml->edit.backcolor;
2906 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2907 imhtml->edit.backcolor = NULL;
2908 }
2909 return imhtml->edit.backcolor != NULL;
2910 }
2911
2912 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face)
2913 {
2914 GtkIMHtmlFormatSpan *span;
2915 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2916 GtkTextIter iter;
2917 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2918 if (face) {
2919 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2920 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2921 span->start_tag = g_strdup_printf("<font face=\"%s\">", face);
2922 span->end = NULL;
2923 span->end_tag = g_strdup("</font>");
2924 span->buffer = imhtml->text_buffer;
2925 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", face, NULL);
2926 imhtml->edit.fontface = span;
2927 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2928 } else {
2929 span = imhtml->edit.fontface;
2930 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2931 imhtml->edit.fontface = NULL;
2932 }
2933 return imhtml->edit.fontface != NULL;
2934 }
2935
2936 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, const char *url, const char *text)
2937 {
2938 GtkIMHtmlFormatSpan *span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2939 GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer);
2940 GtkTextIter iter;
2941 GtkTextTag *tag, *linktag;
2942
2943 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL);
2944 g_object_set_data(G_OBJECT(tag), "link_url", g_strdup(url));
2945
2946 linktag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "LINK");
2947 3127
2948 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); 3128 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark);
2949 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); 3129 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, smiley, &iter);
2950 span->buffer = imhtml->text_buffer; 3130 }
2951 span->start_tag = g_strdup_printf("<a href=\"%s\">", url); 3131
2952 span->end_tag = g_strdup("</a>"); 3132 void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter)
2953 g_signal_connect(G_OBJECT(tag), "event", G_CALLBACK(tag_event), g_strdup(url)); 3133 {
2954
2955 gtk_text_buffer_insert_with_tags(imhtml->text_buffer, &iter, text, strlen(text), linktag, tag, NULL);
2956 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2957 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2958 }
2959
2960 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley)
2961 {
2962 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2963 GtkTextIter iter;
2964 GdkPixbuf *pixbuf = NULL; 3134 GdkPixbuf *pixbuf = NULL;
2965 GdkPixbufAnimation *annipixbuf = NULL; 3135 GdkPixbufAnimation *annipixbuf = NULL;
2966 GtkWidget *icon = NULL; 3136 GtkWidget *icon = NULL;
2967 GtkTextChildAnchor *anchor; 3137 GtkTextChildAnchor *anchor;
2968 char *unescaped = gaim_unescape_html(smiley); 3138 char *unescaped = gaim_unescape_html(smiley);
2969 3139
2970 if (!imhtml->show_smileys) { 3140 if (!imhtml->show_smileys) {
2971 gtk_text_buffer_insert_at_cursor(imhtml->text_buffer, smiley, strlen(smiley)); 3141 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, strlen(smiley));
2972 return; 3142 return;
2973 } 3143 }
2974 3144
2975 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 3145 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
2976 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter);
2977 g_object_set_data(G_OBJECT(anchor), "text_tag", unescaped); 3146 g_object_set_data(G_OBJECT(anchor), "text_tag", unescaped);
2978 3147
2979 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); 3148 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped);
2980 if(annipixbuf) { 3149 if(annipixbuf) {
2981 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { 3150 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) {
2991 gtk_widget_show(icon); 3160 gtk_widget_show(icon);
2992 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); 3161 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor);
2993 } 3162 }
2994 } 3163 }
2995 3164
2996 int span_compare_begin(const GtkIMHtmlFormatSpan *a, const GtkIMHtmlFormatSpan *b, GtkTextBuffer *buffer) 3165 static const gchar *tag_to_html_start(GtkTextTag *tag)
2997 { 3166 {
2998 GtkTextIter ia, ib; 3167 const gchar *name;
2999 gtk_text_buffer_get_iter_at_mark(buffer, &ia, a->start); 3168 static gchar buf[1024];
3000 gtk_text_buffer_get_iter_at_mark(buffer, &ib, b->start); 3169
3001 return gtk_text_iter_compare(&ia, &ib); 3170 name = tag->name;
3002 } 3171 g_return_val_if_fail(name != NULL, "");
3003 3172
3004 int span_compare_end(GtkIMHtmlFormatSpan *a, GtkIMHtmlFormatSpan *b) 3173 if (strcmp(name, "BOLD") == 0) {
3005 { 3174 return "<b>";
3006 GtkTextIter ia, ib; 3175 } else if (strcmp(name, "ITALICS") == 0) {
3007 gtk_text_buffer_get_iter_at_mark(a->buffer, &ia, a->start); 3176 return "<i>";
3008 gtk_text_buffer_get_iter_at_mark(b->buffer, &ib, b->start); 3177 } else if (strcmp(name, "UNDERLINE") == 0) {
3009 /* The -1 here makes it so that if I have two spans that close at the same point, the 3178 return "<u>";
3010 * span added second will be closed first, as in <b><i>Hello</i></b>. Without this, 3179 } else if (strncmp(name, "LINK ", 5) == 0) {
3011 * it would be <b><i>Hello</b></i> I took it out. It started breaking things, and I don't know why*/ 3180 char *tmp = g_object_get_data(G_OBJECT(tag), "link_url");
3012 return gtk_text_iter_compare(&ia, &ib); 3181 if (tmp) {
3182 g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp);
3183 buf[sizeof(buf)-1] = '\0';
3184 return buf;
3185 } else {
3186 return "";
3187 }
3188 } else if (strncmp(name, "FORECOLOR ", 10) == 0) {
3189 g_snprintf(buf, sizeof(buf), "<font color=\"%s\">", &name[10]);
3190 return buf;
3191 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) {
3192 g_snprintf(buf, sizeof(buf), "<font back=\"%s\">", &name[10]);
3193 return buf;
3194 } else if (strncmp(name, "FONT FACE ", 10) == 0) {
3195 g_snprintf(buf, sizeof(buf), "<font face=\"%s\">", &name[10]);
3196 return buf;
3197 } else if (strncmp(name, "FONT SIZE ", 10) == 0) {
3198 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]);
3199 return buf;
3200 } else {
3201 return "";
3202 }
3203 }
3204
3205 static const gchar *tag_to_html_end(GtkTextTag *tag)
3206 {
3207 const gchar *name;
3208
3209 name = tag->name;
3210 g_return_val_if_fail(name != NULL, "");
3211
3212 if (strcmp(name, "BOLD") == 0) {
3213 return "</b>";
3214 } else if (strcmp(name, "ITALICS") == 0) {
3215 return "</i>";
3216 } else if (strcmp(name, "UNDERLINE") == 0) {
3217 return "</u>";
3218 } else if (strncmp(name, "LINK ", 5) == 0) {
3219 return "</a>";
3220 } else if (strncmp(name, "FORECOLOR ", 10) == 0) {
3221 return "</font>";
3222 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) {
3223 return "</font>";
3224 } else if (strncmp(name, "FONT FACE ", 10) == 0) {
3225 return "</font>";
3226 } else if (strncmp(name, "FONT SIZE ", 10) == 0) {
3227 return "</font>";
3228 } else {
3229 return "";
3230 }
3231 }
3232
3233 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter)
3234 {
3235 return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) &&
3236 !gtk_text_iter_has_tag(niter, GTK_TEXT_TAG(tag))) ||
3237 gtk_text_iter_is_end(niter));
3013 } 3238 }
3014 3239
3015 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such 3240 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such
3016 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else 3241 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else
3017 * check the list of formatted strings, sorted by the position of the starting tags and apply them as 3242 * check for tags that are toggled on, insert their html form, and push them on the queue. Then insert
3018 * needed. After applying the start tags, add the end tags to the "closers" list, which is sorted by 3243 * the actual text. Then check for tags that are toggled off and insert them, after checking the queue.
3019 * location of ending tags. These get applied in a similar fashion. Finally, replace <, >, &, and " 3244 * Finally, replace <, >, &, and " with their HTML equivilent.
3020 * with their HTML equivilent. */ 3245 */
3021 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) 3246 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end)
3022 { 3247 {
3023 gunichar c; 3248 gunichar c;
3024 GtkIMHtmlFormatSpan *sspan = NULL, *espan = NULL; 3249 GtkTextIter iter, nextiter;
3025 GtkTextIter iter, siter, eiter;
3026 GList *starters = imhtml->format_spans;
3027 GList *closers = NULL;
3028 GString *str = g_string_new(""); 3250 GString *str = g_string_new("");
3029 3251 GSList *tags, *sl;
3030 g_list_sort_with_data(starters, (GCompareDataFunc)span_compare_begin, imhtml->text_buffer); 3252 GQueue *q, *r;
3253 GtkTextTag *tag;
3254
3255 q = g_queue_new();
3256 r = g_queue_new();
3257
3031 3258
3032 gtk_text_iter_order(start, end); 3259 gtk_text_iter_order(start, end);
3033 iter = *start; 3260 nextiter = iter = *start;
3034 3261 gtk_text_iter_forward_char(&nextiter);
3035 3262
3036 /* Initialize these to the end iter */ 3263 /* First add the tags that are already in progress */
3037 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); 3264 tags = gtk_text_iter_get_tags(start);
3038 eiter = siter; 3265
3039 3266 for (sl = tags; sl; sl = sl->next) {
3040 if (starters) { 3267 tag = sl->data;
3041 while (starters) { 3268 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) {
3042 GtkTextIter tagend; 3269 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tag)));
3043 sspan = (GtkIMHtmlFormatSpan*)starters->data; 3270 g_queue_push_tail(q, tag);
3044 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); 3271 }
3045 if (gtk_text_iter_compare(&siter, start) > 0) 3272 }
3046 break; 3273 g_slist_free(tags);
3047 if (sspan->end) 3274
3048 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &tagend, sspan->end); 3275 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) {
3049 if (sspan->end == NULL || gtk_text_iter_compare(&tagend, start) > 0) { 3276
3050 str = g_string_append(str, sspan->start_tag); 3277 tags = gtk_text_iter_get_tags(&iter);
3051 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end); 3278
3052 espan = (GtkIMHtmlFormatSpan*)closers->data; 3279 for (sl = tags; sl; sl = sl->next) {
3053 /* 3280 tag = sl->data;
3054 * When sending an IM, the following line causes the following warning: 3281 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) {
3055 * Gtk: file gtktextbuffer.c: line 1794 3282 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tag)));
3056 * (gtk_text_buffer_get_iter_at_mark): assertion `GTK_IS_TEXT_MARK (mark)' failed 3283 g_queue_push_tail(q, tag);
3057 *
3058 * The callback path thingy to get here is:
3059 * gtkconv.c, send(), "buf = gtk_imhtml_get_markup(GTK_IMHTML(gtkconv->entry));"
3060 * gtkimhtml.c, gtk_imthml_get_markup(), "return gtk_imhtml_get_markup_range(imhtml, &start, &end);"
3061 *
3062 * I don't really know anything about gtkimhtml, but it almost seems like
3063 * the line above this comments expects to find a closing html tag, but
3064 * can't, for some reason. The warning depends on how much HTML I send
3065 * in my message, kind of.
3066 */
3067 } 3284 }
3068 sspan = (GtkIMHtmlFormatSpan*)starters->data; 3285 }
3069 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); 3286
3070 starters = starters->next; 3287
3071 }
3072 if (!starters) {
3073 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter);
3074 sspan = NULL;
3075 }
3076 }
3077
3078 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) {
3079 if (c == 0xFFFC) { 3288 if (c == 0xFFFC) {
3080 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); 3289 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter);
3081 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); 3290 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag");
3082 str = g_string_append(str, text); 3291 str = g_string_append(str, text);
3292 } else if (c == '<') {
3293 str = g_string_append(str, "&lt;");
3294 } else if (c == '>') {
3295 str = g_string_append(str, "&gt;");
3296 } else if (c == '&') {
3297 str = g_string_append(str, "&amp;");
3298 } else if (c == '"') {
3299 str = g_string_append(str, "&quot;");
3300 } else if (c == '\n') {
3301 str = g_string_append(str, "<br>");
3083 } else { 3302 } else {
3084 while (gtk_text_iter_equal(&eiter, &iter)) { 3303 str = g_string_append_unichar(str, c);
3085 /* This is where we shall insert the ending tag of 3304 }
3086 * this format span */ 3305
3087 str = g_string_append(str, espan->end_tag); 3306 tags = g_slist_reverse(tags);
3088 closers = g_list_remove(closers, espan); 3307 for (sl = tags; sl; sl = sl->next) {
3089 if (!closers) { 3308 tag = sl->data;
3090 espan = NULL; 3309 if (tag_ends_here(tag, &iter, &nextiter)) {
3091 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &eiter); 3310
3092 } else { 3311 GtkTextTag *tmp;
3093 espan = (GtkIMHtmlFormatSpan*)closers->data; 3312
3094 if (espan->end) 3313 while ((tmp = g_queue_pop_tail(q)) != tag) {
3095 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); 3314 if (tmp == NULL)
3096 else { 3315 break;
3097 gtk_text_iter_forward_to_end(&eiter); 3316
3098 } 3317 if (!tag_ends_here(tmp, &iter, &nextiter))
3318 g_queue_push_tail(r, tmp);
3319 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp)));
3320 }
3321
3322 if (tmp == NULL)
3323 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n");
3324 else
3325 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag)));
3326
3327 while ((tmp = g_queue_pop_head(r))) {
3328 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp)));
3329 g_queue_push_tail(q, tmp);
3099 } 3330 }
3100 } 3331 }
3101 while (gtk_text_iter_equal(&siter, &iter)) { 3332 }
3102 /* This is where we shall insert the starting tag of 3333
3103 * this format span */ 3334 g_slist_free(tags);
3104 str = g_string_append(str, sspan->start_tag);
3105 if (sspan->end) {
3106 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end);
3107 espan = (GtkIMHtmlFormatSpan*)closers->data;
3108 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end);
3109
3110 }
3111 starters = starters->next;
3112 if (starters) {
3113 sspan = (GtkIMHtmlFormatSpan*)starters->data;
3114 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start);
3115 } else {
3116 sspan = NULL;
3117 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter);
3118 }
3119
3120 }
3121
3122 if (c == '<')
3123 str = g_string_append(str, "&lt;");
3124 else if (c == '>')
3125 str = g_string_append(str, "&gt;");
3126 else if (c == '&')
3127 str = g_string_append(str, "&amp;");
3128 else if (c == '"')
3129 str = g_string_append(str, "&quot;");
3130 else if (c == '\n')
3131 str = g_string_append(str, "<br>");
3132 else
3133 str = g_string_append_unichar(str, c);
3134 }
3135 gtk_text_iter_forward_char(&iter); 3335 gtk_text_iter_forward_char(&iter);
3136 } 3336 gtk_text_iter_forward_char(&nextiter);
3137 while (closers) { 3337 }
3138 GtkIMHtmlFormatSpan *span = (GtkIMHtmlFormatSpan*)closers->data; 3338
3139 str = g_string_append(str, span->end_tag); 3339 while ((tag = g_queue_pop_tail(q)))
3140 closers = g_list_remove(closers, span); 3340 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag)));
3141 3341
3142 } 3342 g_queue_free(q);
3343 g_queue_free(r);
3143 return g_string_free(str, FALSE); 3344 return g_string_free(str, FALSE);
3144 } 3345 }
3145 3346
3146 void gtk_imhtml_close_tags(GtkIMHtml *imhtml) 3347 void gtk_imhtml_close_tags(GtkIMHtml *imhtml)
3147 { 3348 {
3349 GtkTextIter iter;
3148 3350
3149 if (imhtml->edit.bold) 3351 if (imhtml->edit.bold)
3150 gtk_imhtml_toggle_bold(imhtml); 3352 gtk_imhtml_toggle_bold(imhtml);
3151 3353
3152 if (imhtml->edit.italic) 3354 if (imhtml->edit.italic)
3162 gtk_imhtml_toggle_backcolor(imhtml, NULL); 3364 gtk_imhtml_toggle_backcolor(imhtml, NULL);
3163 3365
3164 if (imhtml->edit.fontface) 3366 if (imhtml->edit.fontface)
3165 gtk_imhtml_toggle_fontface(imhtml, NULL); 3367 gtk_imhtml_toggle_fontface(imhtml, NULL);
3166 3368
3167 if (imhtml->edit.sizespan) 3369 imhtml->edit.fontsize = 0;
3168 gtk_imhtml_font_set_size(imhtml, -1); 3370
3371 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter);
3372 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, &iter, &iter);
3169 3373
3170 } 3374 }
3171 3375
3172 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) 3376 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml)
3173 { 3377 {
3176 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); 3380 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
3177 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); 3381 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
3178 return gtk_imhtml_get_markup_range(imhtml, &start, &end); 3382 return gtk_imhtml_get_markup_range(imhtml, &start, &end);
3179 } 3383 }
3180 3384
3181 char *gtk_imhtml_get_text(GtkIMHtml *imhtml) 3385 char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml)
3386 {
3387 int i, j, lines;
3388 GtkTextIter start, end;
3389 char **ret;
3390
3391 lines = gtk_text_buffer_get_line_count(imhtml->text_buffer);
3392 ret = g_new0(char *, lines + 1);
3393 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
3394 end = start;
3395 gtk_text_iter_forward_to_line_end(&end);
3396
3397 for (i = 0, j = 0; i < lines; i++) {
3398 ret[j] = gtk_imhtml_get_markup_range(imhtml, &start, &end);
3399 if (ret[j] != NULL)
3400 j++;
3401 gtk_text_iter_forward_line(&start);
3402 end = start;
3403 gtk_text_iter_forward_to_line_end(&end);
3404 }
3405
3406 return ret;
3407 }
3408
3409 char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop)
3182 { 3410 {
3183 GString *str = g_string_new(""); 3411 GString *str = g_string_new("");
3184 GtkTextIter iter, end; 3412 GtkTextIter iter, end;
3185 gunichar c; 3413 gunichar c;
3186 3414
3187 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); 3415 if (start == NULL)
3188 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); 3416 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter);
3417 else
3418 iter = *start;
3419
3420 if (stop == NULL)
3421 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
3422 else
3423 end = *stop;
3424
3425 gtk_text_iter_order(&iter, &end);
3189 3426
3190 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { 3427 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) {
3191 if (c == 0xFFFC) { 3428 if (c == 0xFFFC) {
3192 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); 3429 GtkTextChildAnchor* anchor;
3193 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); 3430 char *text = NULL;
3194 str = g_string_append(str, text); 3431
3432 anchor = gtk_text_iter_get_child_anchor(&iter);
3433 if (anchor)
3434 text = g_object_get_data(G_OBJECT(anchor), "text_tag");
3435 if (text)
3436 str = g_string_append(str, text);
3195 } else { 3437 } else {
3196 g_string_append_unichar(str, c); 3438 g_string_append_unichar(str, c);
3197 } 3439 }
3198 gtk_text_iter_forward_char(&iter); 3440 gtk_text_iter_forward_char(&iter);
3199 } 3441 }