1 /* GAIL - The GNOME Accessibility Implementation Library
2 * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <sys/types.h>
26 #include <glib-object.h>
27 #include <glib/gstdio.h>
29 #include "gailtextview.h"
30 #include <libgail-util/gailmisc.h>
32 static void gail_text_view_class_init (GailTextViewClass *klass);
33 static void gail_text_view_init (GailTextView *text_view);
35 static void gail_text_view_real_initialize (AtkObject *obj,
37 static void gail_text_view_real_notify_gtk (GObject *obj,
40 static void gail_text_view_finalize (GObject *object);
42 static void atk_text_interface_init (AtkTextIface *iface);
46 static AtkStateSet* gail_text_view_ref_state_set (AtkObject *accessible);
50 static gchar* gail_text_view_get_text_after_offset (AtkText *text,
52 AtkTextBoundary boundary_type,
55 static gchar* gail_text_view_get_text_at_offset (AtkText *text,
57 AtkTextBoundary boundary_type,
60 static gchar* gail_text_view_get_text_before_offset (AtkText *text,
62 AtkTextBoundary boundary_type,
65 static gchar* gail_text_view_get_text (AtkText*text,
68 static gunichar gail_text_view_get_character_at_offset (AtkText *text,
70 static gint gail_text_view_get_character_count (AtkText *text);
71 static gint gail_text_view_get_caret_offset (AtkText *text);
72 static gboolean gail_text_view_set_caret_offset (AtkText *text,
74 static gint gail_text_view_get_offset_at_point (AtkText *text,
78 static gint gail_text_view_get_n_selections (AtkText *text);
79 static gchar* gail_text_view_get_selection (AtkText *text,
83 static gboolean gail_text_view_add_selection (AtkText *text,
86 static gboolean gail_text_view_remove_selection (AtkText *text,
88 static gboolean gail_text_view_set_selection (AtkText *text,
92 static void gail_text_view_get_character_extents (AtkText *text,
99 static AtkAttributeSet * gail_text_view_get_run_attributes
104 static AtkAttributeSet * gail_text_view_get_default_attributes
106 /* atkeditabletext.h */
108 static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
109 static gboolean gail_text_view_set_run_attributes (AtkEditableText *text,
110 AtkAttributeSet *attrib_set,
113 static void gail_text_view_set_text_contents (AtkEditableText *text,
114 const gchar *string);
115 static void gail_text_view_insert_text (AtkEditableText *text,
119 static void gail_text_view_copy_text (AtkEditableText *text,
122 static void gail_text_view_cut_text (AtkEditableText *text,
125 static void gail_text_view_delete_text (AtkEditableText *text,
128 static void gail_text_view_paste_text (AtkEditableText *text,
130 static void gail_text_view_paste_received (GtkClipboard *clipboard,
133 /* AtkStreamableContent */
134 static void atk_streamable_content_interface_init (AtkStreamableContentIface *iface);
135 static gint gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable);
136 static G_CONST_RETURN gchar* gail_streamable_content_get_mime_type (AtkStreamableContent *streamable,
138 static GIOChannel* gail_streamable_content_get_stream (AtkStreamableContent *streamable,
139 const gchar *mime_type);
140 /* getURI requires atk-1.12.0 or later
141 static void gail_streamable_content_get_uri (AtkStreamableContent *streamable);
146 static void _gail_text_view_insert_text_cb (GtkTextBuffer *buffer,
151 static void _gail_text_view_delete_range_cb (GtkTextBuffer *buffer,
155 static void _gail_text_view_changed_cb (GtkTextBuffer *buffer,
157 static void _gail_text_view_mark_set_cb (GtkTextBuffer *buffer,
161 static gchar* get_text_near_offset (AtkText *text,
162 GailOffsetType function,
163 AtkTextBoundary boundary_type,
167 static gint get_insert_offset (GtkTextBuffer *buffer);
168 static gint get_selection_bound (GtkTextBuffer *buffer);
169 static void emit_text_caret_moved (GailTextView *gail_text_view,
171 static gint insert_idle_handler (gpointer data);
173 typedef struct _GailTextViewPaste GailTextViewPaste;
175 struct _GailTextViewPaste
177 GtkTextBuffer* buffer;
181 G_DEFINE_TYPE_WITH_CODE (GailTextView, gail_text_view, GAIL_TYPE_CONTAINER,
182 G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
183 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
184 G_IMPLEMENT_INTERFACE (ATK_TYPE_STREAMABLE_CONTENT, atk_streamable_content_interface_init))
187 gail_text_view_class_init (GailTextViewClass *klass)
189 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
190 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
191 GailWidgetClass *widget_class;
193 widget_class = (GailWidgetClass*)klass;
195 gobject_class->finalize = gail_text_view_finalize;
197 class->ref_state_set = gail_text_view_ref_state_set;
198 class->initialize = gail_text_view_real_initialize;
200 widget_class->notify_gtk = gail_text_view_real_notify_gtk;
204 gail_text_view_init (GailTextView *text_view)
206 text_view->textutil = NULL;
207 text_view->signal_name = NULL;
208 text_view->previous_insert_offset = -1;
209 text_view->previous_selection_bound = -1;
210 text_view->insert_notify_handler = 0;
214 setup_buffer (GtkTextView *view,
215 GailTextView *gail_view)
217 GtkTextBuffer *buffer;
219 buffer = gtk_text_view_get_buffer (view);
221 if (gail_view->textutil)
222 g_object_unref (gail_view->textutil);
224 gail_view->textutil = gail_text_util_new ();
225 gail_text_util_buffer_setup (gail_view->textutil, buffer);
227 /* Set up signal callbacks */
228 g_signal_connect_data (buffer, "insert-text",
229 (GCallback) _gail_text_view_insert_text_cb, view, NULL, 0);
230 g_signal_connect_data (buffer, "delete-range",
231 (GCallback) _gail_text_view_delete_range_cb, view, NULL, 0);
232 g_signal_connect_data (buffer, "mark-set",
233 (GCallback) _gail_text_view_mark_set_cb, view, NULL, 0);
234 g_signal_connect_data (buffer, "changed",
235 (GCallback) _gail_text_view_changed_cb, view, NULL, 0);
240 gail_text_view_real_initialize (AtkObject *obj,
244 GailTextView *gail_view;
246 ATK_OBJECT_CLASS (gail_text_view_parent_class)->initialize (obj, data);
248 view = GTK_TEXT_VIEW (data);
250 gail_view = GAIL_TEXT_VIEW (obj);
251 setup_buffer (view, gail_view);
253 obj->role = ATK_ROLE_TEXT;
258 gail_text_view_finalize (GObject *object)
260 GailTextView *text_view = GAIL_TEXT_VIEW (object);
262 g_object_unref (text_view->textutil);
263 if (text_view->insert_notify_handler)
264 g_source_remove (text_view->insert_notify_handler);
266 G_OBJECT_CLASS (gail_text_view_parent_class)->finalize (object);
270 gail_text_view_real_notify_gtk (GObject *obj,
273 if (!strcmp (pspec->name, "editable"))
278 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj));
279 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj));
280 atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE,
283 else if (!strcmp (pspec->name, "buffer"))
287 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj));
288 setup_buffer (GTK_TEXT_VIEW (obj), GAIL_TEXT_VIEW (atk_obj));
291 GAIL_WIDGET_CLASS (gail_text_view_parent_class)->notify_gtk (obj, pspec);
297 gail_text_view_ref_state_set (AtkObject *accessible)
299 AtkStateSet *state_set;
300 GtkTextView *text_view;
303 state_set = ATK_OBJECT_CLASS (gail_text_view_parent_class)->ref_state_set (accessible);
304 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
309 text_view = GTK_TEXT_VIEW (widget);
311 if (gtk_text_view_get_editable (text_view))
312 atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
313 atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE);
321 atk_text_interface_init (AtkTextIface *iface)
323 iface->get_text = gail_text_view_get_text;
324 iface->get_text_after_offset = gail_text_view_get_text_after_offset;
325 iface->get_text_at_offset = gail_text_view_get_text_at_offset;
326 iface->get_text_before_offset = gail_text_view_get_text_before_offset;
327 iface->get_character_at_offset = gail_text_view_get_character_at_offset;
328 iface->get_character_count = gail_text_view_get_character_count;
329 iface->get_caret_offset = gail_text_view_get_caret_offset;
330 iface->set_caret_offset = gail_text_view_set_caret_offset;
331 iface->get_offset_at_point = gail_text_view_get_offset_at_point;
332 iface->get_character_extents = gail_text_view_get_character_extents;
333 iface->get_n_selections = gail_text_view_get_n_selections;
334 iface->get_selection = gail_text_view_get_selection;
335 iface->add_selection = gail_text_view_add_selection;
336 iface->remove_selection = gail_text_view_remove_selection;
337 iface->set_selection = gail_text_view_set_selection;
338 iface->get_run_attributes = gail_text_view_get_run_attributes;
339 iface->get_default_attributes = gail_text_view_get_default_attributes;
343 gail_text_view_get_text (AtkText *text,
348 GtkTextBuffer *buffer;
349 GtkTextIter start, end;
352 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
354 /* State is defunct */
357 view = GTK_TEXT_VIEW (widget);
358 buffer = gtk_text_view_get_buffer (view);
359 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
360 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
362 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
366 gail_text_view_get_text_after_offset (AtkText *text,
368 AtkTextBoundary boundary_type,
374 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
376 /* State is defunct */
379 return get_text_near_offset (text, GAIL_AFTER_OFFSET,
380 boundary_type, offset,
381 start_offset, end_offset);
385 gail_text_view_get_text_at_offset (AtkText *text,
387 AtkTextBoundary boundary_type,
393 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
395 /* State is defunct */
398 return get_text_near_offset (text, GAIL_AT_OFFSET,
399 boundary_type, offset,
400 start_offset, end_offset);
404 gail_text_view_get_text_before_offset (AtkText *text,
406 AtkTextBoundary boundary_type,
412 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
414 /* State is defunct */
417 return get_text_near_offset (text, GAIL_BEFORE_OFFSET,
418 boundary_type, offset,
419 start_offset, end_offset);
423 gail_text_view_get_character_at_offset (AtkText *text,
427 GtkTextIter start, end;
428 GtkTextBuffer *buffer;
432 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
436 buffer = GAIL_TEXT_VIEW (text)->textutil->buffer;
437 if (offset >= gtk_text_buffer_get_char_count (buffer))
440 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
442 gtk_text_iter_forward_char (&end);
443 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
444 unichar = g_utf8_get_char (string);
450 gail_text_view_get_character_count (AtkText *text)
453 GtkTextBuffer *buffer;
456 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
458 /* State is defunct */
461 view = GTK_TEXT_VIEW (widget);
462 buffer = gtk_text_view_get_buffer (view);
463 return gtk_text_buffer_get_char_count (buffer);
467 gail_text_view_get_caret_offset (AtkText *text)
472 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
474 /* State is defunct */
477 view = GTK_TEXT_VIEW (widget);
478 return get_insert_offset (gtk_text_view_get_buffer (view));
482 gail_text_view_set_caret_offset (AtkText *text,
487 GtkTextBuffer *buffer;
490 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
492 /* State is defunct */
495 view = GTK_TEXT_VIEW (widget);
496 buffer = gtk_text_view_get_buffer (view);
498 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, offset);
499 gtk_text_buffer_place_cursor (buffer, &pos_itr);
500 gtk_text_view_scroll_to_iter (view, &pos_itr, 0, FALSE, 0, 0);
505 gail_text_view_get_offset_at_point (AtkText *text,
511 GtkTextBuffer *buffer;
513 gint x_widget, y_widget, x_window, y_window, buff_x, buff_y;
518 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
520 /* State is defunct */
523 view = GTK_TEXT_VIEW (widget);
524 buffer = gtk_text_view_get_buffer (view);
526 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
527 gdk_window_get_origin (window, &x_widget, &y_widget);
529 if (coords == ATK_XY_SCREEN)
534 else if (coords == ATK_XY_WINDOW)
536 window = gdk_window_get_toplevel (window);
537 gdk_window_get_origin (window, &x_window, &y_window);
539 x = x - x_widget + x_window;
540 y = y - y_widget + y_window;
545 gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_WIDGET,
546 x, y, &buff_x, &buff_y);
547 gtk_text_view_get_visible_rect (view, &rect);
549 * Clamp point to visible rectangle
551 buff_x = CLAMP (buff_x, rect.x, rect.x + rect.width - 1);
552 buff_y = CLAMP (buff_y, rect.y, rect.y + rect.height - 1);
554 gtk_text_view_get_iter_at_location (view, &loc_itr, buff_x, buff_y);
556 * The iter at a location sometimes points to the next character.
557 * See bug 111031. We work around that
559 gtk_text_view_get_iter_location (view, &loc_itr, &rect);
561 gtk_text_iter_backward_char (&loc_itr);
562 return gtk_text_iter_get_offset (&loc_itr);
566 gail_text_view_get_character_extents (AtkText *text,
575 GtkTextBuffer *buffer;
578 GdkRectangle rectangle;
580 gint x_widget, y_widget, x_window, y_window;
582 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
584 /* State is defunct */
587 view = GTK_TEXT_VIEW (widget);
588 buffer = gtk_text_view_get_buffer (view);
589 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
590 gtk_text_view_get_iter_location (view, &iter, &rectangle);
592 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
593 gdk_window_get_origin (window, &x_widget, &y_widget);
595 *height = rectangle.height;
596 *width = rectangle.width;
598 gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET,
599 rectangle.x, rectangle.y, x, y);
600 if (coords == ATK_XY_WINDOW)
602 window = gdk_window_get_toplevel (window);
603 gdk_window_get_origin (window, &x_window, &y_window);
604 *x += x_widget - x_window;
605 *y += y_widget - y_window;
607 else if (coords == ATK_XY_SCREEN)
621 static AtkAttributeSet*
622 gail_text_view_get_run_attributes (AtkText *text,
628 GtkTextBuffer *buffer;
631 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
633 /* State is defunct */
636 view = GTK_TEXT_VIEW (widget);
637 buffer = gtk_text_view_get_buffer (view);
639 return gail_misc_buffer_get_run_attributes (buffer, offset,
640 start_offset, end_offset);
643 static AtkAttributeSet*
644 add_text_attribute (AtkAttributeSet *attrib_set, AtkTextAttribute attr, gint i)
648 value = atk_text_attribute_get_value (attr, i);
650 return gail_misc_add_attribute (attrib_set, i, g_strdup (value));
653 static AtkAttributeSet*
654 gail_text_view_get_default_attributes (AtkText *text)
658 GtkTextAttributes *text_attrs;
659 AtkAttributeSet *attrib_set = NULL;
660 PangoFontDescription *font;
663 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
665 /* State is defunct */
668 view = GTK_TEXT_VIEW (widget);
669 text_attrs = gtk_text_view_get_default_attributes (view);
671 font = text_attrs->font;
675 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_STYLE,
676 pango_font_description_get_style (font));
678 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_VARIANT,
679 pango_font_description_get_variant (font));
681 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_STRETCH,
682 pango_font_description_get_stretch (font));
684 value = g_strdup (pango_font_description_get_family (font));
685 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FAMILY_NAME, value);
687 value = g_strdup_printf ("%d", pango_font_description_get_weight (font));
688 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_WEIGHT, value);
690 value = g_strdup_printf ("%i", pango_font_description_get_size (font) / PANGO_SCALE);
691 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_SIZE, value);
694 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_JUSTIFICATION, text_attrs->justification);
695 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_DIRECTION, text_attrs->direction);
696 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_WRAP_MODE, text_attrs->wrap_mode);
697 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_EDITABLE, text_attrs->editable);
698 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_INVISIBLE, text_attrs->invisible);
699 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_BG_FULL_HEIGHT, text_attrs->bg_full_height);
701 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_STRIKETHROUGH,
702 text_attrs->appearance.strikethrough);
703 attrib_set = add_text_attribute (attrib_set, ATK_TEXT_ATTR_UNDERLINE,
704 text_attrs->appearance.underline);
706 value = g_strdup_printf ("%u,%u,%u",
707 text_attrs->appearance.bg_color.red,
708 text_attrs->appearance.bg_color.green,
709 text_attrs->appearance.bg_color.blue);
710 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_BG_COLOR, value);
712 value = g_strdup_printf ("%u,%u,%u",
713 text_attrs->appearance.fg_color.red,
714 text_attrs->appearance.fg_color.green,
715 text_attrs->appearance.fg_color.blue);
716 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_FG_COLOR, value);
718 value = g_strdup_printf ("%g", text_attrs->font_scale);
719 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_SCALE, value);
721 value = g_strdup ((gchar *)(text_attrs->language));
722 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LANGUAGE, value);
724 value = g_strdup_printf ("%i", text_attrs->appearance.rise);
725 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_RISE, value);
727 value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
728 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
730 value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
731 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
733 value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
734 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
736 value = g_strdup_printf ("%i", text_attrs->indent);
737 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_INDENT, value);
739 value = g_strdup_printf ("%i", text_attrs->left_margin);
740 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_LEFT_MARGIN, value);
742 value = g_strdup_printf ("%i", text_attrs->right_margin);
743 attrib_set = gail_misc_add_attribute (attrib_set, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
745 gtk_text_attributes_unref (text_attrs);
750 gail_text_view_get_n_selections (AtkText *text)
754 GtkTextBuffer *buffer;
755 GtkTextIter start, end;
756 gint select_start, select_end;
758 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
760 /* State is defunct */
763 view = GTK_TEXT_VIEW (widget);
764 buffer = gtk_text_view_get_buffer (view);
766 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
767 select_start = gtk_text_iter_get_offset (&start);
768 select_end = gtk_text_iter_get_offset (&end);
770 if (select_start != select_end)
777 gail_text_view_get_selection (AtkText *text,
784 GtkTextBuffer *buffer;
785 GtkTextIter start, end;
787 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
789 /* State is defunct */
792 /* Only let the user get the selection if one is set, and if the
793 * selection_num is 0.
795 if (selection_num != 0)
798 view = GTK_TEXT_VIEW (widget);
799 buffer = gtk_text_view_get_buffer (view);
801 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
802 *start_pos = gtk_text_iter_get_offset (&start);
803 *end_pos = gtk_text_iter_get_offset (&end);
805 if (*start_pos != *end_pos)
806 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
812 gail_text_view_add_selection (AtkText *text,
818 GtkTextBuffer *buffer;
820 GtkTextIter start, end;
821 gint select_start, select_end;
823 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
825 /* State is defunct */
828 view = GTK_TEXT_VIEW (widget);
829 buffer = gtk_text_view_get_buffer (view);
831 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
832 select_start = gtk_text_iter_get_offset (&start);
833 select_end = gtk_text_iter_get_offset (&end);
835 /* If there is already a selection, then don't allow another to be added,
836 * since GtkTextView only supports one selected region.
838 if (select_start == select_end)
840 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos);
841 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
842 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos);
843 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
851 gail_text_view_remove_selection (AtkText *text,
856 GtkTextBuffer *buffer;
857 GtkTextMark *cursor_mark;
858 GtkTextIter cursor_itr;
859 GtkTextIter start, end;
860 gint select_start, select_end;
862 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
864 /* State is defunct */
867 if (selection_num != 0)
870 view = GTK_TEXT_VIEW (widget);
871 buffer = gtk_text_view_get_buffer (view);
873 gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
874 select_start = gtk_text_iter_get_offset(&start);
875 select_end = gtk_text_iter_get_offset(&end);
877 if (select_start != select_end)
879 /* Setting the start & end of the selected region to the caret position
880 * turns off the selection.
882 cursor_mark = gtk_text_buffer_get_insert (buffer);
883 gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
884 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr);
892 gail_text_view_set_selection (AtkText *text,
899 GtkTextBuffer *buffer;
901 GtkTextIter start, end;
902 gint select_start, select_end;
904 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
907 /* State is defunct */
911 /* Only let the user move the selection if one is set, and if the
914 if (selection_num != 0)
917 view = GTK_TEXT_VIEW (widget);
918 buffer = gtk_text_view_get_buffer (view);
920 gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
921 select_start = gtk_text_iter_get_offset(&start);
922 select_end = gtk_text_iter_get_offset(&end);
924 if (select_start != select_end)
926 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos);
927 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
928 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos);
929 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
936 /* atkeditabletext.h */
939 atk_editable_text_interface_init (AtkEditableTextIface *iface)
941 iface->set_text_contents = gail_text_view_set_text_contents;
942 iface->insert_text = gail_text_view_insert_text;
943 iface->copy_text = gail_text_view_copy_text;
944 iface->cut_text = gail_text_view_cut_text;
945 iface->delete_text = gail_text_view_delete_text;
946 iface->paste_text = gail_text_view_paste_text;
947 iface->set_run_attributes = gail_text_view_set_run_attributes;
951 gail_text_view_set_run_attributes (AtkEditableText *text,
952 AtkAttributeSet *attrib_set,
957 GtkTextBuffer *buffer;
967 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
969 /* State is defunct */
972 view = GTK_TEXT_VIEW (widget);
973 if (!gtk_text_view_get_editable (view))
976 buffer = gtk_text_view_get_buffer (view);
978 if (attrib_set == NULL)
981 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
982 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
984 tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
986 for (l = attrib_set; l; l = l->next)
997 if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN)))
998 g_object_set (G_OBJECT (tag), "left_margin", atoi (value), NULL);
1000 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN)))
1001 g_object_set (G_OBJECT (tag), "right_margin", atoi (value), NULL);
1003 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT)))
1004 g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL);
1006 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES)))
1007 g_object_set (G_OBJECT (tag), "pixels_above_lines", atoi (value), NULL);
1009 else if (!strcmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES)))
1010 g_object_set (G_OBJECT (tag), "pixels_below_lines", atoi (value), NULL);
1012 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP)))
1013 g_object_set (G_OBJECT (tag), "pixels_inside_wrap", atoi (value), NULL);
1015 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE)))
1016 g_object_set (G_OBJECT (tag), "size", atoi (value), NULL);
1018 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RISE)))
1019 g_object_set (G_OBJECT (tag), "rise", atoi (value), NULL);
1021 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WEIGHT)))
1022 g_object_set (G_OBJECT (tag), "weight", atoi (value), NULL);
1024 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT)))
1026 g_object_set (G_OBJECT (tag), "bg_full_height",
1027 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))),
1031 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LANGUAGE)))
1032 g_object_set (G_OBJECT (tag), "language", value, NULL);
1034 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FAMILY_NAME)))
1035 g_object_set (G_OBJECT (tag), "family", value, NULL);
1037 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_EDITABLE)))
1039 g_object_set (G_OBJECT (tag), "editable",
1040 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
1044 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INVISIBLE)))
1046 g_object_set (G_OBJECT (tag), "invisible",
1047 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
1051 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_UNDERLINE)))
1053 for (j = 0; j < 3; j++)
1055 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, j)))
1057 g_object_set (G_OBJECT (tag), "underline", j, NULL);
1063 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRIKETHROUGH)))
1065 g_object_set (G_OBJECT (tag), "strikethrough",
1066 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0))),
1070 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_COLOR)))
1072 RGB_vals = g_strsplit (value, ",", 3);
1073 color = g_malloc (sizeof (GdkColor));
1074 color->red = atoi (RGB_vals[0]);
1075 color->green = atoi (RGB_vals[1]);
1076 color->blue = atoi (RGB_vals[2]);
1077 g_object_set (G_OBJECT (tag), "background_gdk", color, NULL);
1080 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR)))
1082 RGB_vals = g_strsplit (value, ",", 3);
1083 color = g_malloc (sizeof (GdkColor));
1084 color->red = atoi (RGB_vals[0]);
1085 color->green = atoi (RGB_vals[1]);
1086 color->blue = atoi (RGB_vals[2]);
1087 g_object_set (G_OBJECT (tag), "foreground_gdk", color, NULL);
1090 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH)))
1092 for (j = 0; j < 9; j++)
1094 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, j)))
1096 g_object_set (G_OBJECT (tag), "stretch", j, NULL);
1102 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_JUSTIFICATION)))
1104 for (j = 0; j < 4; j++)
1106 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, j)))
1108 g_object_set (G_OBJECT (tag), "justification", j, NULL);
1114 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_DIRECTION)))
1116 for (j = 0; j < 3; j++)
1118 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, j)))
1120 g_object_set (G_OBJECT (tag), "direction", j, NULL);
1126 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_VARIANT)))
1128 for (j = 0; j < 2; j++)
1130 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, j)))
1132 g_object_set (G_OBJECT (tag), "variant", j, NULL);
1138 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WRAP_MODE)))
1140 for (j = 0; j < 3; j++)
1142 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j)))
1144 g_object_set (G_OBJECT (tag), "wrap_mode", j, NULL);
1150 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STYLE)))
1152 for (j = 0; j < 3; j++)
1154 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, j)))
1156 g_object_set (G_OBJECT (tag), "style", j, NULL);
1166 gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
1172 gail_text_view_set_text_contents (AtkEditableText *text,
1173 const gchar *string)
1177 GtkTextBuffer *buffer;
1179 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1181 /* State is defunct */
1184 view = GTK_TEXT_VIEW (widget);
1185 if (!gtk_text_view_get_editable (view))
1187 buffer = gtk_text_view_get_buffer (view);
1189 /* The -1 indicates that the input string must be null-terminated */
1190 gtk_text_buffer_set_text (buffer, string, -1);
1194 gail_text_view_insert_text (AtkEditableText *text,
1195 const gchar *string,
1201 GtkTextBuffer *buffer;
1202 GtkTextIter pos_itr;
1204 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1206 /* State is defunct */
1209 view = GTK_TEXT_VIEW (widget);
1210 if (!gtk_text_view_get_editable (view))
1212 buffer = gtk_text_view_get_buffer (view);
1214 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, *position);
1215 gtk_text_buffer_insert (buffer, &pos_itr, string, length);
1219 gail_text_view_copy_text (AtkEditableText *text,
1225 GtkTextBuffer *buffer;
1226 GtkTextIter start, end;
1228 GtkClipboard *clipboard;
1230 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1232 /* State is defunct */
1235 view = GTK_TEXT_VIEW (widget);
1236 buffer = gtk_text_view_get_buffer (view);
1238 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1239 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1240 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1241 clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
1242 GDK_SELECTION_CLIPBOARD);
1243 gtk_clipboard_set_text (clipboard, str, -1);
1247 gail_text_view_cut_text (AtkEditableText *text,
1253 GtkTextBuffer *buffer;
1254 GtkTextIter start, end;
1256 GtkClipboard *clipboard;
1258 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1260 /* State is defunct */
1263 view = GTK_TEXT_VIEW (widget);
1264 if (!gtk_text_view_get_editable (view))
1266 buffer = gtk_text_view_get_buffer (view);
1268 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1269 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1270 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1271 clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
1272 GDK_SELECTION_CLIPBOARD);
1273 gtk_clipboard_set_text (clipboard, str, -1);
1274 gtk_text_buffer_delete (buffer, &start, &end);
1278 gail_text_view_delete_text (AtkEditableText *text,
1284 GtkTextBuffer *buffer;
1285 GtkTextIter start_itr;
1286 GtkTextIter end_itr;
1288 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1290 /* State is defunct */
1293 view = GTK_TEXT_VIEW (widget);
1294 if (!gtk_text_view_get_editable (view))
1296 buffer = gtk_text_view_get_buffer (view);
1298 gtk_text_buffer_get_iter_at_offset (buffer, &start_itr, start_pos);
1299 gtk_text_buffer_get_iter_at_offset (buffer, &end_itr, end_pos);
1300 gtk_text_buffer_delete (buffer, &start_itr, &end_itr);
1304 gail_text_view_paste_text (AtkEditableText *text,
1309 GtkTextBuffer *buffer;
1310 GailTextViewPaste paste_struct;
1311 GtkClipboard *clipboard;
1313 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1315 /* State is defunct */
1318 view = GTK_TEXT_VIEW (widget);
1319 if (!gtk_text_view_get_editable (view))
1321 buffer = gtk_text_view_get_buffer (view);
1323 paste_struct.buffer = buffer;
1324 paste_struct.position = position;
1326 g_object_ref (paste_struct.buffer);
1327 clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
1328 GDK_SELECTION_CLIPBOARD);
1329 gtk_clipboard_request_text (clipboard,
1330 gail_text_view_paste_received, &paste_struct);
1334 gail_text_view_paste_received (GtkClipboard *clipboard,
1338 GailTextViewPaste* paste_struct = (GailTextViewPaste *)data;
1339 GtkTextIter pos_itr;
1343 gtk_text_buffer_get_iter_at_offset (paste_struct->buffer, &pos_itr,
1344 paste_struct->position);
1345 gtk_text_buffer_insert (paste_struct->buffer, &pos_itr, text, -1);
1348 g_object_unref (paste_struct->buffer);
1353 /* Note arg1 returns the start of the insert range, arg3 returns the
1354 * end of the insert range if multiple characters are inserted. If one
1355 * character is inserted they have the same value, which is the caret
1356 * location. arg2 returns the begin location of the insert.
1359 _gail_text_view_insert_text_cb (GtkTextBuffer *buffer,
1365 GtkTextView *text = (GtkTextView *) user_data;
1366 AtkObject *accessible;
1367 GailTextView *gail_text_view;
1371 g_return_if_fail (arg3 > 0);
1373 accessible = gtk_widget_get_accessible(GTK_WIDGET(text));
1374 gail_text_view = GAIL_TEXT_VIEW (accessible);
1376 gail_text_view->signal_name = "text_changed::insert";
1377 position = gtk_text_iter_get_offset (arg1);
1378 length = g_utf8_strlen(arg2, arg3);
1380 if (gail_text_view->length == 0)
1382 gail_text_view->position = position;
1383 gail_text_view->length = length;
1385 else if (gail_text_view->position + gail_text_view->length == position)
1387 gail_text_view->length += length;
1392 * We have a non-contiguous insert so report what we have
1394 if (gail_text_view->insert_notify_handler)
1396 g_source_remove (gail_text_view->insert_notify_handler);
1398 gail_text_view->insert_notify_handler = 0;
1399 insert_idle_handler (gail_text_view);
1400 gail_text_view->position = position;
1401 gail_text_view->length = length;
1405 * The signal will be emitted when the changed signal is received
1409 /* Note arg1 returns the start of the delete range, arg2 returns the
1410 * end of the delete range if multiple characters are deleted. If one
1411 * character is deleted they have the same value, which is the caret
1415 _gail_text_view_delete_range_cb (GtkTextBuffer *buffer,
1420 GtkTextView *text = (GtkTextView *) user_data;
1421 AtkObject *accessible;
1422 GailTextView *gail_text_view;
1423 gint offset = gtk_text_iter_get_offset (arg1);
1424 gint length = gtk_text_iter_get_offset (arg2) - offset;
1426 accessible = gtk_widget_get_accessible(GTK_WIDGET(text));
1427 gail_text_view = GAIL_TEXT_VIEW (accessible);
1428 if (gail_text_view->insert_notify_handler)
1430 g_source_remove (gail_text_view->insert_notify_handler);
1431 gail_text_view->insert_notify_handler = 0;
1432 if (gail_text_view->position == offset &&
1433 gail_text_view->length == length)
1436 * Do not bother with insert and delete notifications
1438 gail_text_view->signal_name = NULL;
1439 gail_text_view->position = 0;
1440 gail_text_view->length = 0;
1444 insert_idle_handler (gail_text_view);
1446 g_signal_emit_by_name (accessible, "text_changed::delete",
1450 /* Note arg1 and arg2 point to the same offset, which is the caret
1451 * position after the move
1454 _gail_text_view_mark_set_cb (GtkTextBuffer *buffer,
1459 GtkTextView *text = (GtkTextView *) user_data;
1460 AtkObject *accessible;
1461 GailTextView *gail_text_view;
1462 const char *mark_name = gtk_text_mark_get_name(arg2);
1464 accessible = gtk_widget_get_accessible(GTK_WIDGET(text));
1465 gail_text_view = GAIL_TEXT_VIEW (accessible);
1468 * Only generate the signal for the "insert" mark, which
1469 * represents the cursor.
1471 if (mark_name && !strcmp(mark_name, "insert"))
1473 int insert_offset, selection_bound;
1474 gboolean selection_changed;
1476 insert_offset = gtk_text_iter_get_offset (arg1);
1478 selection_bound = get_selection_bound (buffer);
1479 if (selection_bound != insert_offset)
1481 if (selection_bound != gail_text_view->previous_selection_bound ||
1482 insert_offset != gail_text_view->previous_insert_offset)
1484 selection_changed = TRUE;
1488 selection_changed = FALSE;
1491 else if (gail_text_view->previous_selection_bound != gail_text_view->previous_insert_offset)
1493 selection_changed = TRUE;
1497 selection_changed = FALSE;
1500 emit_text_caret_moved (gail_text_view, insert_offset);
1502 * insert and selection_bound marks are different to a selection
1505 if (selection_changed)
1506 g_signal_emit_by_name (accessible, "text_selection_changed");
1507 gail_text_view->previous_selection_bound = selection_bound;
1512 _gail_text_view_changed_cb (GtkTextBuffer *buffer,
1515 GtkTextView *text = (GtkTextView *) user_data;
1516 AtkObject *accessible;
1517 GailTextView *gail_text_view;
1519 accessible = gtk_widget_get_accessible (GTK_WIDGET (text));
1520 gail_text_view = GAIL_TEXT_VIEW (accessible);
1521 if (gail_text_view->signal_name)
1523 if (!gail_text_view->insert_notify_handler)
1525 gail_text_view->insert_notify_handler = gdk_threads_add_idle (insert_idle_handler, accessible);
1529 emit_text_caret_moved (gail_text_view, get_insert_offset (buffer));
1530 gail_text_view->previous_selection_bound = get_selection_bound (buffer);
1534 get_text_near_offset (AtkText *text,
1535 GailOffsetType function,
1536 AtkTextBoundary boundary_type,
1542 gpointer layout = NULL;
1544 view = GTK_TEXT_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (text)));
1547 * Pass the GtkTextView to the function gail_text_util_get_text()
1548 * so it can find the start and end of the current line on the display.
1550 if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START ||
1551 boundary_type == ATK_TEXT_BOUNDARY_LINE_END)
1554 return gail_text_util_get_text (GAIL_TEXT_VIEW (text)->textutil, layout,
1555 function, boundary_type, offset,
1556 start_offset, end_offset);
1560 get_insert_offset (GtkTextBuffer *buffer)
1562 GtkTextMark *cursor_mark;
1563 GtkTextIter cursor_itr;
1565 cursor_mark = gtk_text_buffer_get_insert (buffer);
1566 gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
1567 return gtk_text_iter_get_offset (&cursor_itr);
1571 get_selection_bound (GtkTextBuffer *buffer)
1573 GtkTextMark *selection_mark;
1574 GtkTextIter selection_itr;
1576 selection_mark = gtk_text_buffer_get_selection_bound (buffer);
1577 gtk_text_buffer_get_iter_at_mark (buffer, &selection_itr, selection_mark);
1578 return gtk_text_iter_get_offset (&selection_itr);
1582 emit_text_caret_moved (GailTextView *gail_text_view,
1586 * If we have text which has been inserted notify the user
1588 if (gail_text_view->insert_notify_handler)
1590 g_source_remove (gail_text_view->insert_notify_handler);
1591 gail_text_view->insert_notify_handler = 0;
1592 insert_idle_handler (gail_text_view);
1595 if (insert_offset != gail_text_view->previous_insert_offset)
1598 * If the caret position has not changed then don't bother notifying
1600 * When mouse click is used to change caret position, notification
1601 * is received on button down and button up.
1603 g_signal_emit_by_name (gail_text_view, "text_caret_moved", insert_offset);
1604 gail_text_view->previous_insert_offset = insert_offset;
1609 insert_idle_handler (gpointer data)
1611 GailTextView *gail_text_view;
1612 GtkTextBuffer *buffer;
1614 gail_text_view = GAIL_TEXT_VIEW (data);
1616 g_signal_emit_by_name (data,
1617 gail_text_view->signal_name,
1618 gail_text_view->position,
1619 gail_text_view->length);
1620 gail_text_view->signal_name = NULL;
1621 gail_text_view->position = 0;
1622 gail_text_view->length = 0;
1624 buffer = gail_text_view->textutil->buffer;
1625 if (gail_text_view->insert_notify_handler)
1628 * If called from idle handler notify caret moved
1630 gail_text_view->insert_notify_handler = 0;
1631 emit_text_caret_moved (gail_text_view, get_insert_offset (buffer));
1632 gail_text_view->previous_selection_bound = get_selection_bound (buffer);
1639 atk_streamable_content_interface_init (AtkStreamableContentIface *iface)
1641 iface->get_n_mime_types = gail_streamable_content_get_n_mime_types;
1642 iface->get_mime_type = gail_streamable_content_get_mime_type;
1643 iface->get_stream = gail_streamable_content_get_stream;
1646 static gint gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable)
1648 gint n_mime_types = 0;
1650 if (GAIL_IS_TEXT_VIEW (streamable) && GAIL_TEXT_VIEW (streamable)->textutil)
1653 gboolean advertises_plaintext = FALSE;
1655 gtk_text_buffer_get_serialize_formats (
1656 GAIL_TEXT_VIEW (streamable)->textutil->buffer,
1658 for (i = 0; i < n_mime_types-1; ++i)
1659 if (!strcmp ("text/plain", gdk_atom_name (atoms[i])))
1660 advertises_plaintext = TRUE;
1661 if (!advertises_plaintext) ++n_mime_types;
1662 /* we support text/plain even if the GtkTextBuffer doesn't */
1664 return n_mime_types;
1667 static G_CONST_RETURN gchar*
1668 gail_streamable_content_get_mime_type (AtkStreamableContent *streamable, gint i)
1670 if (GAIL_IS_TEXT_VIEW (streamable) && GAIL_TEXT_VIEW (streamable)->textutil)
1672 gint n_mime_types = 0;
1674 atoms = gtk_text_buffer_get_serialize_formats (
1675 GAIL_TEXT_VIEW (streamable)->textutil->buffer,
1677 if (i < n_mime_types)
1679 return gdk_atom_name (atoms [i]);
1681 else if (i == n_mime_types)
1682 return "text/plain";
1687 static GIOChannel* gail_streamable_content_get_stream (AtkStreamableContent *streamable,
1688 const gchar *mime_type)
1690 gint i, n_mime_types = 0;
1692 if (!GAIL_IS_TEXT_VIEW (streamable) || !GAIL_TEXT_VIEW (streamable)->textutil)
1694 atoms = gtk_text_buffer_get_serialize_formats (
1695 GAIL_TEXT_VIEW (streamable)->textutil->buffer,
1697 for (i = 0; i < n_mime_types; ++i)
1699 if (!strcmp ("text/plain", mime_type) ||
1700 !strcmp (gdk_atom_name (atoms[i]), mime_type)) {
1701 GtkTextBuffer *buffer;
1706 GtkTextIter start, end;
1707 GIOChannel *gio = NULL;
1709 buffer = GAIL_TEXT_VIEW (streamable)->textutil->buffer;
1710 gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
1711 gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
1712 if (!strcmp ("text/plain", mime_type))
1714 cbuf = (guint8*) gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1715 len = strlen ((const char *) cbuf);
1719 cbuf = gtk_text_buffer_serialize (buffer, buffer, atoms[i], &start, &end, &len);
1721 g_snprintf (tname, 20, "streamXXXXXX");
1722 fd = g_mkstemp (tname);
1723 gio = g_io_channel_unix_new (fd);
1724 g_io_channel_set_encoding (gio, NULL, &err);
1725 if (!err) g_io_channel_write_chars (gio, (const char *) cbuf, (gssize) len, &written, &err);
1726 else g_message ("%s", err->message);
1727 if (!err) g_io_channel_seek_position (gio, 0, G_SEEK_SET, &err);
1728 else g_message ("%s", err->message);
1729 if (!err) g_io_channel_flush (gio, &err);
1730 else g_message ("%s", err->message);
1732 g_message ("<error writing to stream [%s]>", tname);
1735 /* make sure the file is removed on unref of the giochannel */