Mercurial > pidgin.yaz
diff src/gtkimhtml.c @ 7988:d9e831876c28
[gaim-migrate @ 8665]
Here's my best attempt to rip WYSIWYG editing out of gaim, kicking and
screaming all the way.
We'll be releasing 0.75 in the very near future, once the translators are
alerted, and any bugs from this dissection show themselves.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Sun, 04 Jan 2004 06:59:09 +0000 |
parents | aca39f227ea0 |
children | 096562205906 |
line wrap: on
line diff
--- a/src/gtkimhtml.c Sun Jan 04 05:14:39 2004 +0000 +++ b/src/gtkimhtml.c Sun Jan 04 06:59:09 2004 +0000 @@ -59,30 +59,12 @@ #define TOOLTIP_TIMEOUT 500 -static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); -void gtk_imhtml_close_tags(GtkIMHtml *imhtml); - /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ #define MAX_FONT_SIZE 7 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; -enum { - TARGET_HTML, - TARGET_UTF8_STRING, - TARGET_COMPOUND_TEXT, - TARGET_STRING, - TARGET_TEXT -}; - -GtkTargetEntry selection_targets[] = { - { "text/html", 0, TARGET_HTML }, - { "UTF8_STRING", 0, TARGET_UTF8_STRING }, - { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, - { "STRING", 0, TARGET_STRING }, - { "TEXT", 0, TARGET_TEXT}}; - static GtkSmileyTree* gtk_smiley_tree_new () { @@ -114,12 +96,12 @@ t->children [index] = g_new0 (GtkSmileyTree, 1); } else index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str); - + t = t->children [index]; - + x++; } - + t->image = smiley; } @@ -171,7 +153,7 @@ layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); - gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, + gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, "tooltip", 0, 0, -1, -1); @@ -197,7 +179,7 @@ imhtml->tip_timer = 0; return FALSE; } - + if (imhtml->tip_window){ gtk_widget_destroy (imhtml->tip_window); imhtml->tip_window = NULL; @@ -219,12 +201,12 @@ pango_layout_get_pixel_size(layout, &scr_w, NULL); - gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + + gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + pango_font_metrics_get_descent(font))/ 4); if (gap < 2) gap = 2; - baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + + baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + pango_font_metrics_get_descent(font)); w = 8 + scr_w; h = 8 + baseline_skip; @@ -242,7 +224,7 @@ else if (x < 0) x = 0; - y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + + y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + pango_font_metrics_get_descent(font)); gtk_widget_set_size_request (imhtml->tip_window, w, h); @@ -256,7 +238,7 @@ } gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) -{ +{ GtkTextIter iter; GdkWindow *win = event->window; int x, y; @@ -276,7 +258,7 @@ break; templist = templist->next; } - + if (GTK_IMHTML(imhtml)->tip) { if ((tip == GTK_IMHTML(imhtml)->tip)) { return FALSE; @@ -286,22 +268,18 @@ gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); GTK_IMHTML(imhtml)->tip_window = NULL; } - if (GTK_IMHTML(imhtml)->editable) - gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->text_cursor); - else - gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); + gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); if (GTK_IMHTML(imhtml)->tip_timer) g_source_remove(GTK_IMHTML(imhtml)->tip_timer); GTK_IMHTML(imhtml)->tip_timer = 0; } - + if(tip){ - if (!GTK_IMHTML(imhtml)->editable) - gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); - GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, + gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); + GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, gtk_imhtml_tip, imhtml); } - + GTK_IMHTML(imhtml)->tip = tip; g_slist_free(tags); return FALSE; @@ -318,10 +296,7 @@ g_source_remove(GTK_IMHTML(imhtml)->tip_timer); GTK_IMHTML(imhtml)->tip_timer = 0; } - if (GTK_IMHTML(imhtml)->editable) - gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->text_cursor); - else - gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); + gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); /* propogate the event normally */ return FALSE; @@ -330,11 +305,11 @@ /* * XXX - This should be removed eventually. * - * This function exists to work around a gross bug in GtkTextView. - * Basically, we short circuit ctrl+a and ctrl+end because they make + * This function exists to work around a gross bug in GtkTextView. + * Basically, we short circuit ctrl+a and ctrl+end because they make * el program go boom. * - * It's supposed to be fixed in gtk2.2. You can view the bug report at + * It's supposed to be fixed in gtk2.2. You can view the bug report at * http://bugzilla.gnome.org/show_bug.cgi?id=107939 */ gboolean gtk_key_pressed_cb(GtkWidget *imhtml, GdkEventKey *event, gpointer data) @@ -358,107 +333,62 @@ } #if GTK_CHECK_VERSION(2,2,0) -static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { - GtkTextIter start, end; - GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - char *text; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); - - - if (info == TARGET_HTML) { - int len; - GString *str = g_string_new(NULL); - text = gtk_imhtml_get_markup_range(imhtml, &start, &end); - - /* Mozilla asks that we start our text/html with the Unicode byte order mark */ - str = g_string_append_unichar(str, 0xfeff); - str = g_string_append(str, text); - str = g_string_append_unichar(str, 0x0000); - char *selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL); - gtk_selection_data_set (selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len); - g_string_free(str, TRUE); - g_free(selection); - } else { - text = gtk_text_buffer_get_text(imhtml->text_buffer, &start, &end, FALSE); - gtk_selection_data_set_text(selection_data, text, strlen(text)); - } - g_free(text); -} - -static void gtk_imhtml_primary_clipboard_clear(GtkClipboard *clipboard, GtkIMHtml *imhtml) +static GtkIMHtmlCopyable *gtk_imhtml_copyable_new(GtkIMHtml *imhtml, GtkTextMark *mark, const gchar *text) { - GtkTextIter insert; - GtkTextIter selection_bound; - - gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &insert, - gtk_text_buffer_get_mark (imhtml->text_buffer, "insert")); - gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &selection_bound, - gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound")); - - if (!gtk_text_iter_equal (&insert, &selection_bound)) - gtk_text_buffer_move_mark (imhtml->text_buffer, - gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"), - &insert); + GtkIMHtmlCopyable *copy = g_malloc(sizeof(GtkIMHtmlCopyable)); + copy->mark = mark; + copy->text = g_strdup(text); + imhtml->copyables = g_slist_append(imhtml->copyables, copy); + return copy; } static void copy_clipboard_cb(GtkIMHtml *imhtml, GtkClipboard *clipboard) { - gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), - selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), - (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, - (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); - - g_signal_stop_emission_by_name(imhtml, "copy-clipboard"); -} + GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); + GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); + GtkTextIter start, end, smiley, last; + GString *str = g_string_new(NULL); + char *text; -static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) -{ - char *text; - guint16 c; - GtkIMHtml *imhtml = data; + GSList *copyables; + + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); + + if (gtk_text_iter_equal(&start, &end)) + return; + + gtk_text_iter_order(&start, &end); + last = start; - if (selection_data->length < 0) { - text = gtk_clipboard_wait_for_text(clipboard); - } else { - text = g_malloc((selection_data->format / 8) * selection_data->length); - memcpy(text, selection_data->data, selection_data->length * (selection_data->format / 8)); + for (copyables = imhtml->copyables; copyables != NULL; copyables = copyables->next) { + GtkIMHtmlCopyable *copy = GTK_IMHTML_COPYABLE(copyables->data); + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &smiley, copy->mark); + if (gtk_text_iter_compare(&end, &smiley) < 0) { + break; + } + if (gtk_text_iter_compare(&last, &smiley) <= 0) { + text = gtk_text_buffer_get_text(imhtml->text_buffer, &last, &smiley, FALSE); + str = g_string_append(str, text); + str = g_string_append(str, copy->text); + last = smiley; + g_free(text); + } } - - memcpy (&c, text, 2); - if (c == 0xfeff) { - /* This is UCS2 */ - char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL); - g_free(text); - text = utf8; - } - gtk_imhtml_close_tags(imhtml); - gtk_imhtml_append_text_with_images(imhtml, text, GTK_IMHTML_NO_NEWLINE, NULL); -} - - -static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah) -{ - - GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); - gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), - paste_received_cb, imhtml); - g_signal_stop_emission_by_name(imhtml, "paste-clipboard"); + text = gtk_text_buffer_get_text(imhtml->text_buffer, &last, &end, FALSE); + str = g_string_append(str, text); + g_free(text); + + if (!gtk_text_iter_equal(&start, &last)) + gtk_clipboard_set_text(clipboard ? clipboard : + gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), + str->str, str->len); + g_string_free(str, TRUE); } static gboolean button_release_cb(GtkIMHtml *imhtml, GdkEventButton event, gpointer the_foibles_of_man) { - GtkClipboard *clipboard; - if (event.button == 1) { - if ((clipboard = gtk_widget_get_clipboard (GTK_WIDGET (imhtml), - GDK_SELECTION_PRIMARY))) - gtk_text_buffer_remove_selection_clipboard (imhtml->text_buffer, clipboard); - gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY), - selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), - (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, - (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml)); - } + copy_clipboard_cb(imhtml, gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY)); return FALSE; } #endif @@ -478,12 +408,14 @@ { GtkIMHtml *imhtml = GTK_IMHTML(object); GList *scalables; - +#if GTK_CHECK_VERSION(2,2,0) + GSList *copyables; +#endif + g_hash_table_destroy(imhtml->smiley_data); gtk_smiley_tree_destroy(imhtml->default_smilies); gdk_cursor_unref(imhtml->hand_cursor); gdk_cursor_unref(imhtml->arrow_cursor); - gdk_cursor_unref(imhtml->text_cursor); if(imhtml->tip_window){ gtk_widget_destroy(imhtml->tip_window); } @@ -494,7 +426,14 @@ GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); scale->free(scale); } - + +#if GTK_CHECK_VERSION(2,2,0) + for (copyables = imhtml->copyables; copyables; copyables = copyables->next) { + GtkIMHtmlCopyable *copy = GTK_IMHTML_COPYABLE(copyables->data); + g_free(copy->text); + g_free(copy); + } +#endif g_list_free(imhtml->scalables); G_OBJECT_CLASS(parent_class)->finalize (object); } @@ -527,12 +466,13 @@ imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); + gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), FALSE); gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); - /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/ + gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), FALSE); /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ - + /* These tags will be used often and can be reused--we create them on init and then apply them by name - * other tags (color, size, face, etc.) will have to be created and applied dynamically */ + * other tags (color, size, face, etc.) will have to be created and applied dynamically */ gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); @@ -541,11 +481,10 @@ gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); - gtk_text_buffer_create_tag(imhtml->text_buffer, "LINK", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); + /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); - imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); imhtml->show_smileys = TRUE; imhtml->show_comments = TRUE; @@ -558,10 +497,8 @@ g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); - g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); #if GTK_CHECK_VERSION(2,2,0) g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); - g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); g_signal_connect(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml); #endif gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); @@ -570,21 +507,10 @@ imhtml->tip_timer = 0; imhtml->tip_window = NULL; - imhtml->edit.bold = NULL; - imhtml->edit.italic = NULL; - imhtml->edit.underline = NULL; - imhtml->edit.forecolor = NULL; - imhtml->edit.backcolor = NULL; - imhtml->edit.fontface = NULL; - imhtml->edit.sizespan = NULL; - imhtml->edit.fontsize = 3; - - imhtml->format_spans = NULL; - imhtml->scalables = NULL; - - gtk_imhtml_set_editable(imhtml, FALSE); - +#if GTK_CHECK_VERSION(2,2,0) + imhtml->copyables = NULL; +#endif } GtkWidget *gtk_imhtml_new(void *a, void *b) @@ -623,8 +549,9 @@ static void url_open(GtkWidget *w, struct url_data *data) { if(!data) return; + g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); - + g_object_unref(data->object); g_free(data->url); g_free(data); @@ -643,10 +570,9 @@ /* The callback for an event on a link tag. */ gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) { GdkEventButton *event_button = (GdkEventButton *) event; - if (GTK_IMHTML(imhtml)->editable) - return FALSE; + if (event->type == GDK_BUTTON_RELEASE) { - if (event_button->button == 1) { + if (event_button->button == 1) { GtkTextIter start, end; /* we shouldn't open a URL if the user has selected something: */ gtk_text_buffer_get_selection_bounds( @@ -674,10 +600,7 @@ g_source_remove(GTK_IMHTML(imhtml)->tip_timer); GTK_IMHTML(imhtml)->tip_timer = 0; } - if (GTK_IMHTML(imhtml)->editable) - gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); - else - gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); + gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); menu = gtk_menu_new(); /* buttons and such */ @@ -970,11 +893,9 @@ gint *len, gint *type) { - char *close; *type = 1; - - if (!(close = strchr (string, '>'))) + if (!strchr (string, '>')) return FALSE; VALID_TAG ("B"); @@ -1039,8 +960,7 @@ VALID_TAG ("/SPAN"); VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ VALID_TAG ("IMG"); - VALID_OPT_TAG ("BR"); /* see comment 2 lines up */ - + if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { gchar *e = strstr (string + strlen("!--"), "-->"); if (e) { @@ -1048,12 +968,9 @@ *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); return TRUE; } - } - - *type = -1; - *len = close - string + 1; - *tag = g_strndup(string, *len - 1); - return TRUE; + } + + return FALSE; } static gchar* @@ -1116,18 +1033,85 @@ } + +#define NEW_TEXT_BIT 0 +#define NEW_COMMENT_BIT 2 +#define NEW_SCALABLE_BIT 1 +#define NEW_BIT(x) ws [wpos] = '\0'; \ + mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \ + gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \ + gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \ + gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \ + if (bold) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \ + if (italics) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \ + if (underline) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \ + if (strike) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &siter, &iter); \ + if (sub) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUB", &siter, &iter); \ + if (sup) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUP", &siter, &iter); \ + if (pre) \ + gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "PRE", &siter, &iter); \ + if (bg) { \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + } \ + if (fonts) { \ + GtkIMHtmlFontDetail *fd = fonts->data; \ + if (fd->fore) { \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + } \ + if (fd->back) { \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + } \ + if (fd->face) { \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", fd->face, NULL); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + } \ + if (fd->size) { \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "size-points", (double)POINT_SIZE(fd->size), NULL); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + } \ + } \ + if (url) { \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ + g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), g_strdup(url)); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); \ + g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \ + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ + } \ + wpos = 0; \ + ws[0] = 0; \ + gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ + if (x == NEW_SCALABLE_BIT) { \ + GdkRectangle rect; \ + gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); \ + scalable->add_to(scalable, imhtml, &iter); \ + scalable->scale(scalable, rect.width, rect.height); \ + imhtml->scalables = g_list_append(imhtml->scalables, scalable); \ + gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ + } \ + + + GString* gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, const gchar *text, GtkIMHtmlOptions options, GSList *images) { - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter insert; - GdkRectangle rect; gint pos = 0; GString *str = NULL; - GtkTextIter iter; - GtkTextMark *mark; + GtkTextIter iter, siter; + GtkTextMark *mark, *mark2; + GtkTextTag *texttag; gchar *ws; gchar *tag; gchar *url = NULL; @@ -1145,17 +1129,19 @@ sub = 0, sup = 0, title = 0, - pre = 0; + pre = 0; GSList *fonts = NULL; - GtkIMHtmlScalable *scalable = NULL; + + GdkRectangle rect; int y, height; + GtkIMHtmlScalable *scalable = NULL; g_return_val_if_fail (imhtml != NULL, NULL); g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); g_return_val_if_fail (text != NULL, NULL); - printf("Appending: %s\n", text); + c = text; len = strlen(text); ws = g_malloc(len + 1); @@ -1164,22 +1150,13 @@ if (options & GTK_IMHTML_RETURN_LOG) str = g_string_new(""); - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &insert, ins); - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE); - gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); + gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); -#if GTK_CHECK_VERSION(2,2,0) - gtk_imhtml_primary_clipboard_clear(NULL, imhtml); -#endif - gtk_text_buffer_move_mark (imhtml->text_buffer, - gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"), - &iter); - - if(((y + height) - (rect.y + rect.height)) > height + if(((y + height) - (rect.y + rect.height)) > height && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ options |= GTK_IMHTML_NO_SCROLL; } @@ -1188,123 +1165,85 @@ if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { c++; pos++; - ws[wpos] = '\0'; - switch (type) + switch (type) { case 1: /* B */ case 2: /* BOLD */ case 54: /* STRONG */ - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - if (bold == 0) - gtk_imhtml_toggle_bold(imhtml); + NEW_BIT (NEW_TEXT_BIT); bold++; - ws[0] = '\0'; wpos = 0; break; case 3: /* /B */ case 4: /* /BOLD */ case 55: /* /STRONG */ - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - + NEW_BIT (NEW_TEXT_BIT); if (bold) bold--; - if (bold == 0) - gtk_imhtml_toggle_bold(imhtml); break; case 5: /* I */ case 6: /* ITALIC */ case 52: /* EM */ - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - if (italics == 0) - gtk_imhtml_toggle_italic(imhtml); + NEW_BIT (NEW_TEXT_BIT); italics++; break; case 7: /* /I */ case 8: /* /ITALIC */ case 53: /* /EM */ - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; + NEW_BIT (NEW_TEXT_BIT); if (italics) italics--; - if (italics == 0) - gtk_imhtml_toggle_italic(imhtml); break; case 9: /* U */ case 10: /* UNDERLINE */ - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - if (underline == 0) - gtk_imhtml_toggle_underline(imhtml); + NEW_BIT (NEW_TEXT_BIT); underline++; break; case 11: /* /U */ case 12: /* /UNDERLINE */ - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; + NEW_BIT (NEW_TEXT_BIT); if (underline) underline--; - if (underline == 0) - gtk_imhtml_toggle_underline(imhtml); break; case 13: /* S */ case 14: /* STRIKE */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); strike++; break; case 15: /* /S */ case 16: /* /STRIKE */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); if (strike) strike--; break; case 17: /* SUB */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); sub++; break; case 18: /* /SUB */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); if (sub) sub--; break; case 19: /* SUP */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); sup++; break; case 20: /* /SUP */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); if (sup) sup--; break; case 21: /* PRE */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); pre++; break; case 22: /* /PRE */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); if (pre) pre--; break; case 23: /* TITLE */ - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); title++; break; case 24: /* /TITLE */ @@ -1318,49 +1257,28 @@ break; case 25: /* BR */ case 58: /* BR/ */ - case 60: /* BR (opt) */ ws[wpos] = '\n'; wpos++; - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); break; case 26: /* HR */ case 42: /* HR (opt) */ ws[wpos++] = '\n'; - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); scalable = gtk_imhtml_hr_new(); - gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); - scalable->add_to(scalable, imhtml, &iter); - scalable->scale(scalable, rect.width, rect.height); - imhtml->scalables = g_list_append(imhtml->scalables, scalable); - ws[0] = '\0'; wpos = 0; + NEW_BIT(NEW_SCALABLE_BIT); ws[wpos++] = '\n'; - break; case 27: /* /FONT */ if (fonts) { GtkIMHtmlFontDetail *font = fonts->data; - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); fonts = g_slist_remove (fonts, font); - if (font->face) { - gtk_imhtml_toggle_fontface(imhtml, NULL); + if (font->face) g_free (font->face); - } - if (font->fore) { - gtk_imhtml_toggle_forecolor(imhtml, NULL); + if (font->fore) g_free (font->fore); - } - if (font->back) { - gtk_imhtml_toggle_backcolor(imhtml, NULL); + if (font->back) g_free (font->back); - } if (font->sml) g_free (font->sml); g_free (font); @@ -1368,15 +1286,11 @@ break; case 28: /* /A */ if (url) { - gtk_imhtml_insert_link(imhtml, url, ws); + NEW_BIT(NEW_TEXT_BIT); g_free(url); - ws[0] = '\0'; wpos = 0; url = NULL; - ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); + break; } - break; - case 29: /* P */ case 30: /* /P */ case 31: /* H3 */ @@ -1402,13 +1316,9 @@ sml = gtk_imhtml_get_html_opt (tag, "SML="); if (!(color || back || face || size || sml)) break; - - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - + + NEW_BIT (NEW_TEXT_BIT); + font = g_new0 (GtkIMHtmlFontDetail, 1); if (fonts) oldfont = fonts->data; @@ -1417,22 +1327,20 @@ font->fore = color; else if (oldfont && oldfont->fore) font->fore = g_strdup(oldfont->fore); - if (font->fore) - gtk_imhtml_toggle_forecolor(imhtml, font->fore); if (back && !(options & GTK_IMHTML_NO_COLOURS)) font->back = back; else if (oldfont && oldfont->back) font->back = g_strdup(oldfont->back); - if (font->back) - gtk_imhtml_toggle_backcolor(imhtml, font->back); - + if (face && !(options & GTK_IMHTML_NO_FONTS)) font->face = face; else if (oldfont && oldfont->face) font->face = g_strdup(oldfont->face); - if (font->face) - gtk_imhtml_toggle_fontface(imhtml, font->face); + if (font->face && (atoi(font->face) > 100)) { + g_free(font->face); + font->face = g_strdup("100"); + } if (sml) font->sml = sml; @@ -1448,12 +1356,11 @@ font->size = MAX (0, 3 - font->size); } else if (isdigit (*size)) { sscanf (size, "%hd", &font->size); - } + } if (font->size > 100) font->size = 100; } else if (oldfont) font->size = oldfont->size; - // gtk_imhtml_font_set_size(imhtml, font->size); g_free(size); fonts = g_slist_prepend (fonts, font); } @@ -1462,16 +1369,10 @@ if (!(options & GTK_IMHTML_NO_COLOURS)) { char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); if (bgcolor) { - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - // NEW_BIT(NEW_TEXT_BIT); + NEW_BIT(NEW_TEXT_BIT); if (bg) g_free(bg); bg = bgcolor; - gtk_imhtml_toggle_backcolor(imhtml, bg); } } break; @@ -1479,12 +1380,9 @@ { gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); if (href) { - if (url) { - gtk_imhtml_insert_link(imhtml, url, ws); - g_free(url); - } else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; + NEW_BIT (NEW_TEXT_BIT); + if (url) + g_free (url); url = href; } } @@ -1507,7 +1405,7 @@ } scalable = gtk_imhtml_image_new(img, filename); - //NEW_BIT(NEW_SCALABLE_BIT); + NEW_BIT(NEW_SCALABLE_BIT); g_object_unref(G_OBJECT(img)); } case 47: /* P (opt) */ @@ -1518,11 +1416,11 @@ case 56: /* SPAN */ case 57: /* /SPAN */ break; - case 61: /* comment */ - //NEW_BIT (NEW_TEXT_BIT); + case 60: /* comment */ + NEW_BIT (NEW_TEXT_BIT); if (imhtml->show_comments) wpos = g_snprintf (ws, len, "%s", tag); - // NEW_BIT (NEW_COMMENT_BIT); + NEW_BIT (NEW_COMMENT_BIT); break; default: break; @@ -1541,60 +1439,79 @@ if (!(options & GTK_IMHTML_NO_NEWLINE)) { ws[wpos] = '\n'; wpos++; - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; - wpos = 0; - //NEW_BIT (NEW_TEXT_BIT); + NEW_BIT (NEW_TEXT_BIT); } c++; pos++; } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { + GtkTextChildAnchor *anchor; + GtkWidget *icon = NULL; + GtkTextIter copy; + GdkPixbufAnimation *annipixbuf = NULL; + GdkPixbuf *pixbuf = NULL; GtkIMHtmlFontDetail *fd; - + gchar *sml = NULL; if (fonts) { fd = fonts->data; sml = fd->sml; } - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else { - printf("Inserting %s\n", ws); - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); + NEW_BIT (NEW_TEXT_BIT); + wpos = g_snprintf (ws, smilelen + 1, "%s", c); + anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); + annipixbuf = gtk_smiley_tree_image(imhtml, sml, ws); + if(annipixbuf) { + if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { + pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); + if(pixbuf) + icon = gtk_image_new_from_pixbuf(pixbuf); + } else { + icon = gtk_image_new_from_animation(annipixbuf); + } } - wpos = g_snprintf (ws, smilelen + 1, "%s", c); - gtk_imhtml_insert_smiley(imhtml, sml, ws); - ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - + if (icon) { + gtk_widget_show(icon); + gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); +#if GTK_CHECK_VERSION(2,2,0) + gtk_imhtml_copyable_new(imhtml, + gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE), + ws); +#endif + } + + copy = iter; + gtk_text_iter_backward_char(©); + if (bg) { + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &iter, ©); + } + if (fonts) { + GtkIMHtmlFontDetail *fd = fonts->data; + if (fd->back) { + texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); + gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &iter, ©); + } + } c += smilelen; pos += smilelen; wpos = 0; ws[0] = 0; - } else if (*c) { + } else if (*c) { ws [wpos++] = *c++; pos++; } else { break; } } - if (url) - gtk_imhtml_insert_link(imhtml, url, ws); - else - gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); - ws[0] = '\0'; wpos = 0; - - //NEW_BIT(NEW_TEXT_BIT); + + NEW_BIT(NEW_TEXT_BIT); if (url) { g_free (url); if (str) str = g_string_append (str, "</A>"); } - + while (fonts) { GtkIMHtmlFontDetail *font = fonts->data; fonts = g_slist_remove (fonts, font); @@ -1648,14 +1565,10 @@ g_free (ws); if(bg) g_free(bg); - gtk_imhtml_close_tags(imhtml); if (!(options & GTK_IMHTML_NO_SCROLL)) gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, 0, TRUE, 0.0, 1.0); gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); - gtk_text_buffer_move_mark (imhtml->text_buffer, - gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"), - &iter); return str; } @@ -1683,40 +1596,10 @@ gtk_imhtml_clear (GtkIMHtml *imhtml) { GtkTextIter start, end; - GList *del = imhtml->format_spans; - + gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); - - while (imhtml->format_spans) { - GtkIMHtmlFormatSpan *span = imhtml->format_spans->data; - if (span->start_tag) - g_free(span->start_tag); - if (span->end_tag) - g_free(span->end_tag); - g_free(span); - imhtml->format_spans = imhtml->format_spans->next; - } - g_list_free(del); - - del = imhtml->scalables; - while (del) { - GtkIMHtmlScalable *scale = del->data; - scale->free(scale); - del = del->next; - } - g_list_free(imhtml->scalables); - imhtml->scalables = NULL; - - imhtml->edit.bold = NULL; - imhtml->edit.italic = NULL; - imhtml->edit.underline = NULL; - imhtml->edit.fontface = NULL; - imhtml->edit.forecolor = NULL; - imhtml->edit.backcolor = NULL; - imhtml->edit.sizespan = NULL; - imhtml->edit.fontsize = 3; } void gtk_imhtml_page_up (GtkIMHtml *imhtml) @@ -1728,7 +1611,7 @@ gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, rect.y - rect.height); gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); - + } void gtk_imhtml_page_down (GtkIMHtml *imhtml) { @@ -1886,7 +1769,7 @@ g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", G_CALLBACK(gtk_widget_destroy), sel); g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", - G_CALLBACK(gtk_widget_destroy), sel); + G_CALLBACK(gtk_widget_destroy), sel); gtk_widget_show(sel); } @@ -1972,7 +1855,7 @@ { GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); - g_object_set_data(G_OBJECT(anchor), "text_tag", "<hr>"); + gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); } @@ -1988,16 +1871,17 @@ g_return_val_if_fail(imhtml != NULL, FALSE); g_return_val_if_fail(text != NULL, FALSE); - + if (imhtml->search_string && !strcmp(text, imhtml->search_string)) new_search = FALSE; - + + if (new_search) { gtk_imhtml_search_clear(imhtml); gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); } else { gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, - gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); + gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); } imhtml->search_string = g_strdup(text); @@ -2009,27 +1893,24 @@ gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); if (new_search) { gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); - do + do gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); - while (gtk_source_iter_forward_search(&end, imhtml->search_string, - GTK_SOURCE_SEARCH_VISIBLE_ONLY | + while (gtk_source_iter_forward_search(&end, imhtml->search_string, + GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, &start, &end, NULL)); } return TRUE; } - - gtk_imhtml_search_clear(imhtml); - return FALSE; } void gtk_imhtml_search_clear(GtkIMHtml *imhtml) { GtkTextIter start, end; - + g_return_if_fail(imhtml != NULL); - + gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); @@ -2038,546 +1919,3 @@ g_free(imhtml->search_string); imhtml->search_string = NULL; } - -/* Editable stuff */ -static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) -{ - GtkIMHtmlFormatSpan *span = NULL; - GtkTextIter end; - - gtk_text_iter_forward_chars(iter, len); - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); - gtk_text_iter_forward_char(&end); - - if (!gtk_text_iter_equal(&end, iter)) - return; - - - if ((span = imhtml->edit.bold)) { - GtkTextIter bold; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &bold, span->start); - gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &bold, iter); - } - - if ((span = imhtml->edit.italic)) { - GtkTextIter italic; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &italic, span->start); - gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &italic, - iter); - } - - if ((span = imhtml->edit.underline)) { - GtkTextIter underline; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &underline, span->start); - gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &underline, - iter); - } - - if ((span = imhtml->edit.forecolor)) { - GtkTextIter fore; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &fore, span->start); - gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &fore, iter); - } - - if ((span = imhtml->edit.backcolor)) { - GtkTextIter back; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &back, span->start); - gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &back, iter); - } - - if ((span = imhtml->edit.fontface)) { - GtkTextIter face; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &face, span->start); - gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &face, iter); - } - - if ((span = imhtml->edit.sizespan)) { - GtkTextIter size; - /* We create the tags here so that one can grow font or shrink font several times - * in a row without creating unnecessary tags */ - if (span->tag == NULL) { - span->tag = gtk_text_buffer_create_tag - (imhtml->text_buffer, NULL, "size-points", (double)_point_sizes [imhtml->edit.fontsize-1], NULL); - span->start_tag = g_strdup_printf("<font size=\"%d\">", imhtml->edit.fontsize); - span->end_tag = g_strdup("</font>"); - } - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &size, span->start); - gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &size, iter); - } -} - -void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) -{ - gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); - gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); - imhtml->editable = editable; -} - -gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) -{ - return imhtml->editable; -} - -gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (!imhtml->edit.bold) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->start_tag = g_strdup("<b>"); - span->end = NULL; - span->end_tag = g_strdup("</b>"); - span->buffer = imhtml->text_buffer; - span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "BOLD"); - imhtml->edit.bold = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } else { - span = imhtml->edit.bold; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->edit.bold = NULL; - } - return imhtml->edit.bold != NULL; -} - -gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (!imhtml->edit.italic) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->start_tag = g_strdup("<i>"); - span->end = NULL; - span->end_tag = g_strdup("</i>"); - span->buffer = imhtml->text_buffer; - span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "ITALIC"); - imhtml->edit.italic = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } else { - span = imhtml->edit.italic; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->edit.italic = NULL; - } - return imhtml->edit.italic != NULL; -} - -gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (!imhtml->edit.underline) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->start_tag = g_strdup("<u>"); - span->end = NULL; - span->end_tag = g_strdup("</u>"); - span->buffer = imhtml->text_buffer; - span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "UNDERLINE"); - imhtml->edit.underline = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } else { - span = imhtml->edit.underline; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->edit.underline = NULL; - } - return imhtml->edit.underline != NULL; -} - -void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - - imhtml->edit.fontsize = size; - - if (imhtml->edit.sizespan) { - GtkTextIter iter2; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); - if (gtk_text_iter_equal(&iter2, &iter)) - return; - span = imhtml->edit.sizespan; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - } - if (size != -1) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->end = NULL; - span->buffer = imhtml->text_buffer; - span->tag = NULL; - imhtml->edit.sizespan = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } -} - -void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (imhtml->edit.fontsize == 1) - return; - - imhtml->edit.fontsize--; - - if (imhtml->edit.sizespan) { - GtkTextIter iter2; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); - if (gtk_text_iter_equal(&iter2, &iter)) - return; - span = imhtml->edit.sizespan; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - } - - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->end = NULL; - span->buffer = imhtml->text_buffer; - span->tag = NULL; - imhtml->edit.sizespan = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); -} - -void gtk_imhtml_font_grow(GtkIMHtml *imhtml) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (imhtml->edit.fontsize == MAX_FONT_SIZE) - return; - - imhtml->edit.fontsize++; - - if (imhtml->edit.sizespan) { - GtkTextIter iter2; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); - if (gtk_text_iter_equal(&iter2, &iter)) - return; - span = imhtml->edit.sizespan; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - } - - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->end = NULL; - span->tag = NULL; - span->buffer = imhtml->text_buffer; - imhtml->edit.sizespan = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); -} - -gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (!imhtml->edit.forecolor) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->start_tag = g_strdup_printf("<font color=\"%s\">", color); - span->end = NULL; - span->end_tag = g_strdup("</font>"); - span->buffer = imhtml->text_buffer; - span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", color, NULL); - imhtml->edit.forecolor = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } else { - span = imhtml->edit.forecolor; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->edit.forecolor = NULL; - } - - - return imhtml->edit.forecolor != NULL; -} - -gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (!imhtml->edit.backcolor) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->start_tag = g_strdup_printf("<font back=\"%s\">", color); - span->end = NULL; - span->end_tag = g_strdup("</font>"); - span->buffer = imhtml->text_buffer; - span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", color, NULL); - imhtml->edit.backcolor = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } else { - span = imhtml->edit.backcolor; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->edit.backcolor = NULL; - } - return imhtml->edit.backcolor != NULL; -} - -gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) -{ - GtkIMHtmlFormatSpan *span; - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - if (!imhtml->edit.fontface) { - span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->start_tag = g_strdup_printf("<font face=\"%s\">", face); - span->end = NULL; - span->end_tag = g_strdup("</font>"); - span->buffer = imhtml->text_buffer; - span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", face, NULL); - imhtml->edit.fontface = span; - imhtml->format_spans = g_list_append(imhtml->format_spans, span); - } else { - span = imhtml->edit.fontface; - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->edit.fontface = NULL; - } - return imhtml->edit.fontface != NULL; -} - -void gtk_imhtml_insert_link(GtkIMHtml *imhtml, const char *url, const char *text) -{ - GtkIMHtmlFormatSpan *span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); - GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - GtkTextTag *tag, *linktag; - - tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); - g_object_set_data(G_OBJECT(tag), "link_url", g_strdup(url)); - - linktag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "LINK"); - - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); - span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - span->buffer = imhtml->text_buffer; - span->start_tag = g_strdup_printf("<a href=\"%s\">", url); - span->end_tag = g_strdup("</a>"); - g_signal_connect(G_OBJECT(tag), "event", G_CALLBACK(tag_event), g_strdup(url)); - - gtk_text_buffer_insert_with_tags(imhtml->text_buffer, &iter, text, strlen(text), linktag, tag, NULL); - span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); - imhtml->format_spans = g_list_append(imhtml->format_spans, span); -} - -void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) -{ - GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); - GtkTextIter iter; - GdkPixbuf *pixbuf = NULL; - GdkPixbufAnimation *annipixbuf = NULL; - GtkWidget *icon = NULL; - GtkTextChildAnchor *anchor; - - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); - anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); - g_object_set_data(G_OBJECT(anchor), "text_tag", g_strdup(smiley)); - - annipixbuf = gtk_smiley_tree_image(imhtml, sml, smiley); - if(annipixbuf) { - if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { - pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); - if(pixbuf) - icon = gtk_image_new_from_pixbuf(pixbuf); - } else { - icon = gtk_image_new_from_animation(annipixbuf); - } - } - - if (icon) { - gtk_widget_show(icon); - gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); - } -} - -int span_compare_begin(const GtkIMHtmlFormatSpan *a, const GtkIMHtmlFormatSpan *b, GtkTextBuffer *buffer) -{ - GtkTextIter ia, ib; - gtk_text_buffer_get_iter_at_mark(buffer, &ia, a->start); - gtk_text_buffer_get_iter_at_mark(buffer, &ib, b->start); - return gtk_text_iter_compare(&ia, &ib); -} - -int span_compare_end(GtkIMHtmlFormatSpan *a, GtkIMHtmlFormatSpan *b) -{ - GtkTextIter ia, ib; - gtk_text_buffer_get_iter_at_mark(a->buffer, &ia, a->start); - gtk_text_buffer_get_iter_at_mark(b->buffer, &ib, b->start); - /* The -1 here makes it so that if I have two spans that close at the same point, the - * span added second will be closed first, as in <b><i>Hello</i></b>. Without this, - * it would be <b><i>Hello</b></i> */ - return gtk_text_iter_compare(&ia, &ib) - 1; -} - -/* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such - * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else - * check the list of formatted strings, sorted by the position of the starting tags and apply them as - * needed. After applying the start tags, add the end tags to the "closers" list, which is sorted by - * location of ending tags. These get applied in a similar fashion. Finally, replace <, >, &, and " - * with their HTML equivilent. */ -char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) -{ - gunichar c; - GtkIMHtmlFormatSpan *sspan = NULL, *espan = NULL; - GtkTextIter iter, siter, eiter; - GList *starters = imhtml->format_spans; - GList *closers = NULL; - GString *str = g_string_new(""); - g_list_sort_with_data(starters, (GCompareDataFunc)span_compare_begin, imhtml->text_buffer); - - gtk_text_iter_order(start, end); - iter = *start; - - - /* Initialize these to the end iter */ - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); - eiter = siter; - - if (starters) { - while (starters) { - GtkTextIter tagend; - sspan = (GtkIMHtmlFormatSpan*)starters->data; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); - if (gtk_text_iter_compare(&siter, start) > 0) - break; - if (sspan->end) - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &tagend, sspan->end); - if (sspan->end == NULL || gtk_text_iter_compare(&tagend, start) > 0) { - str = g_string_append(str, sspan->start_tag); - closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end); - espan = (GtkIMHtmlFormatSpan*)closers->data; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); - } - sspan = (GtkIMHtmlFormatSpan*)starters->data; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); - starters = starters->next; - } - if (!starters) { - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); - sspan = NULL; - } - } - - while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { - if (c == 0xFFFC) { - GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); - char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); - str = g_string_append(str, text); - } else { - while (gtk_text_iter_equal(&eiter, &iter)) { - /* This is where we shall insert the ending tag of - * this format span */ - str = g_string_append(str, espan->end_tag); - closers = g_list_remove(closers, espan); - if (!closers) { - espan = NULL; - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &eiter); - } else { - espan = (GtkIMHtmlFormatSpan*)closers->data; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); - } - } - while (gtk_text_iter_equal(&siter, &iter)) { - /* This is where we shall insert the starting tag of - * this format span */ - str = g_string_append(str, sspan->start_tag); - if (sspan->end) { - closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end); - espan = (GtkIMHtmlFormatSpan*)closers->data; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); - - } - starters = starters->next; - if (starters) { - sspan = (GtkIMHtmlFormatSpan*)starters->data; - gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); - } else { - sspan = NULL; - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); - } - - } - - if (c == '<') - str = g_string_append(str, "<"); - else if (c == '>') - str = g_string_append(str, ">"); - else if (c == '&') - str = g_string_append(str, "&"); - else if (c == '"') - str = g_string_append(str, """); - else if (c == '\n') - str = g_string_append(str, "<br>"); - else - str = g_string_append_unichar(str, c); - } - gtk_text_iter_forward_char(&iter); - } - while (closers) { - GtkIMHtmlFormatSpan *span = (GtkIMHtmlFormatSpan*)closers->data; - str = g_string_append(str, span->end_tag); - closers = g_list_remove(closers, span); - - } - printf("Gotten: %s\n", str->str); - return g_string_free(str, FALSE); -} - -void gtk_imhtml_close_tags(GtkIMHtml *imhtml) -{ - - if (imhtml->edit.bold) - gtk_imhtml_toggle_bold(imhtml); - - if (imhtml->edit.italic) - gtk_imhtml_toggle_italic(imhtml); - - if (imhtml->edit.underline) - gtk_imhtml_toggle_underline(imhtml); - - if (imhtml->edit.forecolor) - gtk_imhtml_toggle_forecolor(imhtml, NULL); - - if (imhtml->edit.backcolor) - gtk_imhtml_toggle_backcolor(imhtml, NULL); - - if (imhtml->edit.fontface) - gtk_imhtml_toggle_fontface(imhtml, NULL); - - if (imhtml->edit.sizespan) - gtk_imhtml_font_set_size(imhtml, -1); - -} - -char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) -{ - GtkTextIter start, end; - - gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); - return gtk_imhtml_get_markup_range(imhtml, &start, &end); -} - -char *gtk_imhtml_get_text(GtkIMHtml *imhtml) -{ - GtkTextIter start_iter, end_iter; - gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start_iter); - gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end_iter); - return gtk_text_buffer_get_text(imhtml->text_buffer, &start_iter, &end_iter, FALSE); - -} -