8 #include <yui/Libyui_config.h>
9 #include "ygtkrichtext.h"
13 #define IDENT_MARGIN 20
14 #define PARAGRAPH_SPACING 12
17 extern gchar *ygutils_convert_to_xhtml (
const char *instr);
19 G_DEFINE_TYPE (
YGtkRichText, ygtk_rich_text, YGTK_TYPE_TEXT_VIEW)
21 static guint link_clicked_signal;
22 static GdkColor link_color = { 0, 0, 0, 0xeeee };
27 static const char *get_link_at_iter (GtkTextView *text_view, GtkTextIter *iter)
30 GSList *tags = gtk_text_iter_get_tags (iter), *tagp;
31 for (tagp = tags; tagp != NULL; tagp = tagp->next) {
32 GtkTextTag *tag = (GtkTextTag*) tagp->data;
33 link = (
char*) g_object_get_data (G_OBJECT (tag),
"link");
42 static const char *get_link (GtkTextView *text_view, gint win_x, gint win_y)
44 gint buffer_x, buffer_y;
45 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
46 GTK_TEXT_WINDOW_WIDGET, win_x, win_y, &buffer_x, &buffer_y);
48 gtk_text_view_get_iter_at_location (text_view, &iter, buffer_x, buffer_y);
49 return get_link_at_iter (text_view, &iter);
54 static gboolean event_after (GtkWidget *text_view, GdkEvent *ev)
56 if (ev->type != GDK_BUTTON_RELEASE)
58 GtkTextIter start, end;
59 GtkTextBuffer *buffer;
60 GdkEventButton *
event = (GdkEventButton *) ev;
61 if (event->button != 1)
63 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
66 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
67 if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
70 const char *link = get_link (GTK_TEXT_VIEW (text_view), event->x, event->y);
73 GtkTextMark *mark = gtk_text_buffer_get_mark (buffer, link + 1);
75 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (text_view), mark, 0.4, TRUE, 0, 0);
78 g_signal_emit (YGTK_RICH_TEXT (text_view), link_clicked_signal, 0, link);
85 static int mystrcmp(
void *a,
void *b)
86 {
return g_ascii_strcasecmp (*(
char **)a, *(
char **)b); }
88 static gboolean isBlockTag (
const char *tag)
90 static const char *Tags[] =
91 {
"blockquote",
"dd",
"dl",
"dt",
"h1",
"h2",
"h3",
"h4",
"h5",
"li",
"p",
"pre" };
93 ret = bsearch (&tag, Tags,
sizeof (Tags)/
sizeof(
char*),
sizeof(
char *), (
void*)mystrcmp);
96 static gboolean isIdentTag (
const char *tag)
98 static const char *Tags[] =
99 {
"blockquote",
"dd",
"ol",
"ul" };
101 ret = bsearch (&tag, Tags,
sizeof (Tags)/
sizeof(
char*),
sizeof(
char *), (
void*)mystrcmp);
107 GtkWidget *widget = GTK_WIDGET (rtext);
108 GtkTextView *tview = GTK_TEXT_VIEW (rtext);
109 gtk_text_view_set_editable (tview, FALSE);
110 gtk_text_view_set_wrap_mode (tview, GTK_WRAP_WORD_CHAR);
111 gtk_text_view_set_pixels_below_lines (tview, 4);
112 gtk_text_view_set_left_margin (tview, 4);
115 GdkDisplay *display = gtk_widget_get_display (widget);
116 rtext->hand_cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
117 g_object_ref (rtext->hand_cursor);
119 gtk_widget_style_get (widget,
"link_color", &link_color, NULL);
120 g_signal_connect (tview,
"event-after",
121 G_CALLBACK (event_after), NULL);
124 GtkTextBuffer *buffer = gtk_text_view_get_buffer (tview);
126 gboolean reverse = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL;
127 const char *left_margin = reverse ?
"right-margin" :
"left-margin";
128 const char *right_margin = reverse ?
"left-margin" :
"right-margin";
130 gtk_text_buffer_create_tag (buffer,
"body", NULL);
131 gtk_text_buffer_create_tag (buffer,
"h1",
"weight", PANGO_WEIGHT_HEAVY,
132 "scale", PANGO_SCALE_XX_LARGE,
"pixels-below-lines", 16,
133 "foreground",
"#5c5c5c", NULL);
134 gtk_text_buffer_create_tag (buffer,
"h2",
"weight", PANGO_WEIGHT_ULTRABOLD,
135 "scale", PANGO_SCALE_X_LARGE,
"pixels-below-lines", 15,
136 "foreground",
"#5c5c5c", NULL);
137 gtk_text_buffer_create_tag (buffer,
"h3",
"weight", PANGO_WEIGHT_BOLD,
138 "scale", PANGO_SCALE_LARGE,
"pixels-below-lines", 14,
139 "foreground",
"#5c5c5c", NULL);
140 gtk_text_buffer_create_tag (buffer,
"h4",
"weight", PANGO_WEIGHT_SEMIBOLD,
141 "scale", PANGO_SCALE_LARGE,
"pixels-below-lines", 13,
142 "foreground",
"#5c5c5c", NULL);
143 gtk_text_buffer_create_tag (buffer,
"h5",
144 "scale", PANGO_SCALE_LARGE,
"foreground",
"#5c5c5c", NULL);
145 gtk_text_buffer_create_tag (buffer,
"p",
"pixels-below-lines", 12, NULL);
146 gtk_text_buffer_create_tag (buffer,
"big",
"scale", PANGO_SCALE_LARGE, NULL);
147 gtk_text_buffer_create_tag (buffer,
"small",
"scale", PANGO_SCALE_SMALL, NULL);
148 gtk_text_buffer_create_tag (buffer,
"tt",
"family",
"monospace", NULL);
149 gtk_text_buffer_create_tag (buffer,
"pre",
"family",
"monospace",
150 "paragraph-background",
"#f0f0f0", left_margin, 16, right_margin, 20, NULL);
151 gtk_text_buffer_create_tag (buffer,
"b",
"weight", PANGO_WEIGHT_BOLD, NULL);
152 gtk_text_buffer_create_tag (buffer,
"i",
"style", PANGO_STYLE_ITALIC, NULL);
153 gtk_text_buffer_create_tag (buffer,
"u",
"underline", PANGO_UNDERLINE_SINGLE, NULL);
154 gtk_text_buffer_create_tag (buffer,
"center",
"justification", GTK_JUSTIFY_CENTER, NULL);
155 gtk_text_buffer_create_tag (buffer,
"right",
"justification", GTK_JUSTIFY_RIGHT, NULL);
157 gtk_text_buffer_create_tag (buffer,
"keyword",
"background",
"yellow",
158 "foreground",
"#000000", NULL);
161 static void ygtk_rich_text_destroy (GtkWidget *widget)
165 g_object_unref (rtext->hand_cursor);
166 ygtk_rich_text_set_background (rtext, NULL);
167 GTK_WIDGET_CLASS (ygtk_rich_text_parent_class)->destroy(widget);
172 static void set_cursor_if_appropriate (GtkTextView *view, gint wx, gint wy)
175 GtkWidget *widget = GTK_WIDGET (view);
177 gtk_widget_get_allocation(widget, &alloc);
179 GdkWindow *window = gtk_widget_get_window (widget);
180 GdkDisplay *display = gdk_window_get_display (window);
182 # if GTK_CHECK_VERSION (3, 20, 0)
183 GdkSeat *seat = gdk_display_get_default_seat (display);
184 GdkDevice *pointer = gdk_seat_get_pointer (seat);
186 GdkDeviceManager *device_manager = gdk_display_get_device_manager (display);
187 GdkDevice *pointer = gdk_device_manager_get_client_pointer (device_manager);
190 gdk_window_get_device_position (window, pointer, &wx, &wy, NULL);
192 if (wx < 0 || wy < 0 || wx >= alloc.width ||
197 static gboolean hovering_over_link = FALSE;
198 gboolean hovering = get_link (view, wx, wy) != NULL;
200 if (hovering != hovering_over_link) {
201 hovering_over_link = hovering;
203 GdkWindow *window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT);
204 GdkCursor *cursor = hovering ? rtext->hand_cursor : NULL;
205 gdk_window_set_cursor (window, cursor);
210 static gboolean ygtk_rich_text_motion_notify_event (GtkWidget *widget,
211 GdkEventMotion *event)
213 set_cursor_if_appropriate (GTK_TEXT_VIEW (widget), event->x, event->y);
217 static gboolean ygtk_rich_text_draw (GtkWidget *widget, cairo_t *cr)
219 GtkTextView *text = GTK_TEXT_VIEW (widget);
222 gtk_widget_get_allocation(widget, &alloc);
223 if (rtext->background_pixbuf) {
224 GdkWindow *window = gtk_text_view_get_window (text, GTK_TEXT_WINDOW_TEXT);
225 if (gtk_cairo_should_draw_window(cr, window)) {
227 int width = gdk_pixbuf_get_width (rtext->background_pixbuf);
228 int height = gdk_pixbuf_get_height (rtext->background_pixbuf);
229 gtk_text_view_buffer_to_window_coords (text, GTK_TEXT_WINDOW_TEXT,
230 alloc.width-((2*width)/5), -height/3, &x, &y);
232 gtk_cairo_transform_to_window(cr, widget, window);
233 gdk_cairo_set_source_pixbuf (cr, rtext->background_pixbuf, x, y);
239 ret = GTK_WIDGET_CLASS (ygtk_rich_text_parent_class)->draw (widget, cr);
240 set_cursor_if_appropriate (text, -1, -1);
252 static void HTMLList_init (
HTMLList *list, gboolean ordered)
254 list->ordered = ordered;
255 list->enumeration = 1;
263 GtkTextBuffer *buffer;
264 GtkTextTagTable *tags;
269 gboolean default_color;
272 gboolean closed_block_tag;
275 static void GRTParseState_init (
GRTParseState *state, GtkTextBuffer *buffer)
277 state->buffer = buffer;
278 state->pre_mode = FALSE;
279 state->default_color = TRUE;
280 state->left_margin = 0;
281 state->tags = gtk_text_buffer_get_tag_table (buffer);
282 state->html_list = NULL;
284 state->closed_block_tag = FALSE;
287 static void free_list (GList *list)
290 for (i = g_list_first (list); i; i = i->next)
298 free_list (state->html_list);
299 free_list (state->htags);
302 static void insert_li_enumeration (
GRTParseState *state, GtkTextIter *iter, gboolean start)
304 gboolean _start = gtk_widget_get_default_direction() != GTK_TEXT_DIR_RTL;
305 if (_start != start)
return;
308 if (state->html_list && (front_list = g_list_first (state->html_list)->data) &&
309 (front_list->ordered)) {
310 const gchar *form = start ?
"%d. " :
" .%d";
311 gchar *str = g_strdup_printf (form, front_list->enumeration++);
312 gtk_text_buffer_insert (state->buffer, iter, str, -1);
316 const char *str = start ?
"\u2022 " :
" \u2022";
317 gtk_text_buffer_insert (state->buffer, iter, str, -1);
324 rt_start_element (GMarkupParseContext *context,
325 const gchar *element_name,
326 const gchar **attribute_names,
327 const gchar **attribute_values,
334 gtk_text_buffer_get_end_iter (state->buffer, &iter);
335 tag->mark = gtk_text_buffer_create_mark (state->buffer, NULL, &iter, TRUE);
337 if (!g_ascii_strcasecmp (element_name,
"pre"))
338 state->pre_mode = TRUE;
341 if (isBlockTag (element_name)) {
343 if (state->html_list && gtk_text_iter_get_line_offset (&iter) < 6)
345 else if (!gtk_text_iter_starts_line (&iter)) {
346 gtk_text_buffer_insert (state->buffer, &iter,
"\n", -1);
347 gtk_text_buffer_get_end_iter (state->buffer, &iter);
350 state->closed_block_tag = FALSE;
352 char *lower = g_ascii_strdown (element_name, -1);
353 tag->tag = gtk_text_tag_table_lookup (state->tags, lower);
357 if (!g_ascii_strcasecmp (element_name,
"font")) {
359 for (i = 0; attribute_names[i]; i++) {
360 const char *attrb = attribute_names[i];
361 const char *value = attribute_values[i];
362 if (!g_ascii_strcasecmp (attrb,
"color")) {
363 tag->tag = gtk_text_buffer_create_tag (state->buffer, NULL,
364 "foreground", value, NULL);
365 state->default_color = FALSE;
368 else if (!g_ascii_strcasecmp (attrb,
"bgcolor")) {
369 tag->tag = gtk_text_buffer_create_tag (state->buffer, NULL,
370 "background", value, NULL);
373 g_warning (
"Unknown font attribute: '%s'", attrb);
376 else if (!g_ascii_strcasecmp (element_name,
"a")) {
377 if (attribute_names[0] &&
378 !g_ascii_strcasecmp (attribute_names[0],
"href")) {
379 tag->tag = gtk_text_buffer_create_tag (state->buffer, NULL,
380 "underline", PANGO_UNDERLINE_SINGLE, NULL);
381 if (state->default_color)
382 g_object_set (tag->tag,
"foreground-gdk", &link_color, NULL);
383 g_object_set_data (G_OBJECT (tag->tag),
"link", g_strdup (attribute_values[0]));
385 else if (attribute_names[0] &&
386 !g_ascii_strcasecmp (attribute_names[0],
"name")) {
387 gtk_text_buffer_create_mark (state->buffer, attribute_values[0], &iter, TRUE);
390 g_warning (
"Unknown a attribute: '%s'", attribute_names[0]);
392 else if (!g_ascii_strcasecmp (element_name,
"li"))
393 insert_li_enumeration (state, &iter, TRUE);
395 else if (!g_ascii_strcasecmp (element_name,
"ul") ||
396 !g_ascii_strcasecmp (element_name,
"ol")) {
398 HTMLList_init (list, !g_ascii_strcasecmp (element_name,
"ol"));
399 state->html_list = g_list_append (state->html_list, list);
401 else if (!g_ascii_strcasecmp (element_name,
"img")) {
402 if (attribute_names[0] &&
403 !g_ascii_strcasecmp (attribute_names[0],
"src")) {
404 const char *filename = attribute_values[0];
407 if (filename[0] ==
'/')
408 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
410 pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default(),
411 filename, 64, 0, NULL);
413 gtk_text_buffer_insert_pixbuf (state->buffer, &iter, pixbuf);
414 g_object_unref (G_OBJECT (pixbuf));
419 g_warning (
"Unknown img attribute: '%s'", attribute_names[0]);
423 else if (!g_ascii_strcasecmp (element_name,
"br")) ;
424 else if (!g_ascii_strcasecmp (element_name,
"hr")) ;
428 if (isBlockTag (element_name))
431 g_warning (
"Unknown tag '%s'", element_name);
434 else if (attribute_names[0]) {
435 if (!g_ascii_strcasecmp (element_name,
"p")) {
438 if (!g_ascii_strcasecmp (attribute_names[0],
"bgcolor"))
439 tag->tag = gtk_text_buffer_create_tag (state->buffer, NULL,
440 "paragraph-background", attribute_values[0], NULL);
442 g_warning (
"Unknown p attribute: '%s'", attribute_names[0]);
446 if (!tag->tag && isIdentTag (element_name)) {
447 state->left_margin += IDENT_MARGIN;
449 gboolean reverse = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL;
450 const char *margin = reverse ?
"right-margin" :
"left-margin";
451 tag->tag = gtk_text_buffer_create_tag (state->buffer, NULL,
452 margin, state->left_margin, NULL);
456 state->htags = g_list_append (state->htags, tag);
462 rt_end_element (GMarkupParseContext *context,
463 const gchar *element_name,
469 if (g_list_length (state->htags) == 0) {
470 g_warning (
"Urgh - empty tag queue closing '%s'", element_name);
474 g_return_if_fail (state->htags != NULL);
475 GRTPTag *tag = g_list_last (state->htags)->data;
476 state->htags = g_list_remove (state->htags, tag);
478 GtkTextIter start, end;
479 gtk_text_buffer_get_iter_at_mark (state->buffer, &start, tag->mark);
480 gtk_text_buffer_get_end_iter (state->buffer, &end);
482 gint appendLines = 0;
484 if (isIdentTag (element_name))
485 state->left_margin -= IDENT_MARGIN;
487 if (!g_ascii_strcasecmp (element_name,
"ul") ||
488 !g_ascii_strcasecmp (element_name,
"ol")) {
489 HTMLList *last_list = g_list_last (state->html_list)->data;
490 state->html_list = g_list_remove (state->html_list, last_list);
493 else if (!g_ascii_strcasecmp (element_name,
"font"))
494 state->default_color = TRUE;
496 else if (!g_ascii_strcasecmp (element_name,
"pre"))
497 state->pre_mode = FALSE;
499 else if (!g_ascii_strcasecmp (element_name,
"hr")) {
500 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (hr_xpm);
501 gtk_text_buffer_insert_pixbuf (state->buffer, &end, pixbuf);
502 g_object_unref (pixbuf);
503 gtk_text_buffer_get_iter_at_mark (state->buffer, &start, tag->mark);
504 gtk_text_buffer_get_end_iter (state->buffer, &end);
505 gtk_text_buffer_apply_tag_by_name (state->buffer,
"center", &start, &end);
508 else if (!g_ascii_strcasecmp (element_name,
"li"))
509 insert_li_enumeration (state, &end, FALSE);
511 if (isBlockTag (element_name) || !g_ascii_strcasecmp (element_name,
"br")) {
513 if (isBlockTag (element_name) && gtk_text_iter_starts_line (&end))
515 state->closed_block_tag = TRUE;
518 state->closed_block_tag = FALSE;
521 gtk_text_buffer_insert (state->buffer, &end,
522 appendLines == 1 ?
"\n" :
"\n\n", -1);
523 gtk_text_buffer_get_iter_at_mark (state->buffer, &start, tag->mark);
524 gtk_text_buffer_get_end_iter (state->buffer, &end);
528 gtk_text_buffer_apply_tag (state->buffer, tag->tag, &start, &end);
530 gtk_text_buffer_delete_mark (state->buffer, tag->mark);
535 rt_text (GMarkupParseContext *context,
542 GtkTextIter start, end;
543 gtk_text_buffer_get_end_iter (state->buffer, &start);
545 gtk_text_buffer_insert_with_tags (state->buffer, &start,
546 text, text_len, NULL, NULL);
548 gboolean rtl = gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL;
551 if (state->closed_block_tag) {
552 for (; i < text_len; i++)
553 if (!g_ascii_isspace (text[i]))
558 if (rtl && text[text_len-1] ==
':') {
559 gtk_text_buffer_insert (state->buffer, &start,
":", 1);
563 gtk_text_buffer_insert (state->buffer, &start, text+i, text_len-i);
565 gtk_text_buffer_get_end_iter (state->buffer, &end);
569 rt_passthrough (GMarkupParseContext *context,
570 const gchar *passthrough_text,
579 rt_error (GMarkupParseContext *context,
585 static GMarkupParser rt_parser = {
593 GtkWidget *ygtk_rich_text_new (
void)
594 {
return g_object_new (YGTK_TYPE_RICH_TEXT, NULL); }
596 static void ygtk_rich_text_set_rtl (
YGtkRichText *rtext)
598 GtkTextView *view = GTK_TEXT_VIEW (rtext);
599 GtkTextBuffer *buffer = gtk_text_view_get_buffer (view);
601 gtk_text_buffer_get_start_iter (buffer, &iter);
603 GtkTextIter end = iter;
604 if (!gtk_text_iter_forward_line (&end))
605 gtk_text_buffer_get_end_iter (buffer, &end);
607 gchar *text = gtk_text_iter_get_text (&iter, &end);
608 PangoDirection dir = pango_find_base_dir (text, -1);
609 if (dir == PANGO_DIRECTION_LTR)
610 gtk_text_buffer_apply_tag_by_name (buffer,
"right", &iter, &end);
613 }
while (!gtk_text_iter_is_end (&iter));
616 void ygtk_rich_text_set_plain_text (
YGtkRichText* rtext,
const gchar* text)
618 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rtext));
619 gtk_text_buffer_set_text (buffer, text, -1);
622 void ygtk_rich_text_set_text (
YGtkRichText* rtext,
const gchar* text)
624 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rtext));
625 gtk_text_buffer_set_text (buffer,
"", 0);
628 GRTParseState_init (&state, buffer);
630 GMarkupParseContext *ctx;
631 ctx = g_markup_parse_context_new (&rt_parser, (GMarkupParseFlags)0, &state, NULL);
633 char *xml = ygutils_convert_to_xhtml (text);
634 GError *error = NULL;
635 if (!g_markup_parse_context_parse (ctx, xml, -1, &error)) {
636 g_warning (
"Markup parse error '%s'", error ? error->message :
"Unknown");
640 g_markup_parse_context_free (ctx);
641 GRTParseState_free (&state);
644 GtkTextIter end_it, before_end_it;
645 gtk_text_buffer_get_end_iter (buffer, &end_it);
646 before_end_it = end_it;
647 if (gtk_text_iter_backward_char (&before_end_it) &&
648 gtk_text_iter_get_char (&before_end_it) ==
'\n')
649 gtk_text_buffer_delete (buffer, &before_end_it, &end_it);
653 if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL)
654 ygtk_rich_text_set_rtl (rtext);
660 static gboolean ygtk_rich_text_forward_search (
const GtkTextIter *begin,
661 const GtkTextIter *end,
const gchar *_key, GtkTextIter *match_start,
662 GtkTextIter *match_end)
669 gunichar *key = g_utf8_to_ucs4 (_key, -1, NULL, NULL, NULL);
675 for (k = key; *k; k++)
676 *k = g_unichar_tolower (*k);
678 GtkTextIter iter = *begin, iiter;
679 while (!gtk_text_iter_is_end (&iter) && gtk_text_iter_compare (&iter, end) <= 0) {
681 for (k = key; *k == g_unichar_tolower (gtk_text_iter_get_char (&iiter)) && (*k);
682 k++, gtk_text_iter_forward_char (&iiter))
689 gtk_text_iter_forward_char (&iter);
694 gboolean ygtk_rich_text_mark_text (
YGtkRichText *rtext,
const gchar *text)
696 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rtext));
697 GtkTextIter iter, end, match_start, match_end;
699 gtk_text_buffer_get_bounds (buffer, &iter, &end);
700 gtk_text_buffer_remove_tag_by_name (buffer,
"keyword", &iter, &end);
702 gtk_text_buffer_select_range (buffer, &iter, &iter);
703 if (!text || *text ==
'\0')
706 gboolean found = FALSE;
707 while (ygtk_rich_text_forward_search (&iter, &end, text,
708 &match_start, &match_end)) {
710 gtk_text_buffer_apply_tag_by_name (buffer,
"keyword", &match_start, &match_end);
712 gtk_text_iter_forward_char (&iter);
717 gboolean ygtk_rich_text_forward_mark (
YGtkRichText *rtext,
const gchar *text)
719 GtkTextIter start_iter, end_iter;
720 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rtext));
721 gtk_text_buffer_get_iter_at_mark (buffer, &start_iter,
722 gtk_text_buffer_get_selection_bound (buffer));
723 gtk_text_buffer_get_end_iter (buffer, &end_iter);
726 found = ygtk_rich_text_forward_search (&start_iter, &end_iter, text,
727 &start_iter, &end_iter);
729 gtk_text_buffer_get_start_iter (buffer, &start_iter);
730 found = ygtk_rich_text_forward_search (&start_iter, &end_iter, text,
731 &start_iter, &end_iter);
735 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (rtext), &start_iter, 0.10,
737 gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
743 void ygtk_rich_text_set_background (
YGtkRichText *rtext, GdkPixbuf *pixbuf)
745 if (rtext->background_pixbuf)
746 g_object_unref (G_OBJECT (rtext->background_pixbuf));
747 rtext->background_pixbuf = pixbuf;
749 g_object_ref (G_OBJECT (pixbuf));
754 GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
755 gtkwidget_class->motion_notify_event = ygtk_rich_text_motion_notify_event;
756 gtkwidget_class->draw = ygtk_rich_text_draw;
757 gtkwidget_class->destroy = ygtk_rich_text_destroy;
759 link_clicked_signal = g_signal_new (
"link-clicked",
760 G_TYPE_FROM_CLASS (G_OBJECT_CLASS (klass)), G_SIGNAL_RUN_LAST,
762 g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);