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 "gtktextviewaccessible.h"
33 static void setup_buffer (GtkTextView *view,GtkTextViewAccessible *accessible);
34 static void insert_text_cb (GtkTextBuffer *buffer,
39 static void delete_range_cb (GtkTextBuffer *buffer,
43 static void changed_cb (GtkTextBuffer *buffer,
45 static void mark_set_cb (GtkTextBuffer *buffer,
49 static gint insert_idle_handler (gpointer data);
52 static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
53 static void atk_text_interface_init (AtkTextIface *iface);
54 static void atk_streamable_content_interface_init (AtkStreamableContentIface *iface);
56 G_DEFINE_TYPE_WITH_CODE (GtkTextViewAccessible, gtk_text_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
57 G_IMPLEMENT_INTERFACE (ATK_TYPE_EDITABLE_TEXT, atk_editable_text_interface_init)
58 G_IMPLEMENT_INTERFACE (ATK_TYPE_TEXT, atk_text_interface_init)
59 G_IMPLEMENT_INTERFACE (ATK_TYPE_STREAMABLE_CONTENT, atk_streamable_content_interface_init))
63 gtk_text_view_accessible_initialize (AtkObject *obj,
66 ATK_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->initialize (obj, data);
68 setup_buffer (GTK_TEXT_VIEW (data), GTK_TEXT_VIEW_ACCESSIBLE (obj));
70 obj->role = ATK_ROLE_TEXT;
74 gtk_text_view_accessible_finalize (GObject *object)
76 GtkTextViewAccessible *text_view = GTK_TEXT_VIEW_ACCESSIBLE (object);
78 if (text_view->insert_notify_handler)
79 g_source_remove (text_view->insert_notify_handler);
81 G_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->finalize (object);
85 gtk_text_view_accessible_notify_gtk (GObject *obj,
90 atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj));
92 if (!strcmp (pspec->name, "editable"))
96 editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj));
97 atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, editable);
99 else if (!strcmp (pspec->name, "buffer"))
101 setup_buffer (GTK_TEXT_VIEW (obj), GTK_TEXT_VIEW_ACCESSIBLE (atk_obj));
104 GAIL_WIDGET_CLASS (gtk_text_view_accessible_parent_class)->notify_gtk (obj, pspec);
108 gtk_text_view_accessible_ref_state_set (AtkObject *accessible)
110 AtkStateSet *state_set;
113 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
117 state_set = ATK_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->ref_state_set (accessible);
119 if (gtk_text_view_get_editable (GTK_TEXT_VIEW (widget)))
120 atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
121 atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE);
127 gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
129 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
130 AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
131 GailWidgetClass *widget_class;
133 widget_class = (GailWidgetClass*)klass;
135 gobject_class->finalize = gtk_text_view_accessible_finalize;
137 class->ref_state_set = gtk_text_view_accessible_ref_state_set;
138 class->initialize = gtk_text_view_accessible_initialize;
140 widget_class->notify_gtk = gtk_text_view_accessible_notify_gtk;
144 gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
146 accessible->signal_name = NULL;
147 accessible->previous_insert_offset = -1;
148 accessible->previous_selection_bound = -1;
149 accessible->insert_notify_handler = 0;
153 setup_buffer (GtkTextView *view,
154 GtkTextViewAccessible *accessible)
156 GtkTextBuffer *buffer;
158 buffer = gtk_text_view_get_buffer (view);
160 /* Set up signal callbacks */
161 g_signal_connect_data (buffer, "insert-text",
162 (GCallback) insert_text_cb, view, NULL, 0);
163 g_signal_connect_data (buffer, "delete-range",
164 (GCallback) delete_range_cb, view, NULL, 0);
165 g_signal_connect_data (buffer, "mark-set",
166 (GCallback) mark_set_cb, view, NULL, 0);
167 g_signal_connect_data (buffer, "changed",
168 (GCallback) changed_cb, view, NULL, 0);
173 gtk_text_view_accessible_get_text (AtkText *text,
178 GtkTextBuffer *buffer;
179 GtkTextIter start, end;
182 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
186 view = GTK_TEXT_VIEW (widget);
187 buffer = gtk_text_view_get_buffer (view);
188 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
189 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
191 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
195 gtk_text_view_accessible_get_text_after_offset (AtkText *text,
197 AtkTextBoundary boundary_type,
202 GtkTextBuffer *buffer;
204 GtkTextIter start, end;
206 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
210 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
211 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
212 _gtk_text_buffer_get_text_after (buffer, boundary_type,
214 *start_offset = gtk_text_iter_get_offset (&start);
215 *end_offset = gtk_text_iter_get_offset (&end);
216 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
220 gtk_text_view_accessible_get_text_at_offset (AtkText *text,
222 AtkTextBoundary boundary_type,
227 GtkTextBuffer *buffer;
229 GtkTextIter start, end;
231 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
235 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
236 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
237 _gtk_text_buffer_get_text_at (buffer, boundary_type,
239 *start_offset = gtk_text_iter_get_offset (&start);
240 *end_offset = gtk_text_iter_get_offset (&end);
241 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
245 gtk_text_view_accessible_get_text_before_offset (AtkText *text,
247 AtkTextBoundary boundary_type,
252 GtkTextBuffer *buffer;
254 GtkTextIter start, end;
256 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
260 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
261 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
262 _gtk_text_buffer_get_text_before (buffer, boundary_type,
264 *start_offset = gtk_text_iter_get_offset (&start);
265 *end_offset = gtk_text_iter_get_offset (&end);
266 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
270 gtk_text_view_accessible_get_character_at_offset (AtkText *text,
274 GtkTextIter start, end;
275 GtkTextBuffer *buffer;
279 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
283 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
284 if (offset >= gtk_text_buffer_get_char_count (buffer))
287 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
289 gtk_text_iter_forward_char (&end);
290 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
291 unichar = g_utf8_get_char (string);
298 gtk_text_view_accessible_get_character_count (AtkText *text)
301 GtkTextBuffer *buffer;
303 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
307 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
308 return gtk_text_buffer_get_char_count (buffer);
312 get_insert_offset (GtkTextBuffer *buffer)
317 insert = gtk_text_buffer_get_insert (buffer);
318 gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
319 return gtk_text_iter_get_offset (&iter);
323 gtk_text_view_accessible_get_caret_offset (AtkText *text)
326 GtkTextBuffer *buffer;
328 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
332 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
333 return get_insert_offset (buffer);
337 gtk_text_view_accessible_set_caret_offset (AtkText *text,
342 GtkTextBuffer *buffer;
345 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
349 view = GTK_TEXT_VIEW (widget);
350 buffer = gtk_text_view_get_buffer (view);
352 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
353 gtk_text_buffer_place_cursor (buffer, &iter);
354 gtk_text_view_scroll_to_iter (view, &iter, 0, FALSE, 0, 0);
360 gtk_text_view_accessible_get_offset_at_point (AtkText *text,
367 gint x_widget, y_widget, x_window, y_window, buff_x, buff_y;
372 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
376 view = GTK_TEXT_VIEW (widget);
377 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
378 gdk_window_get_origin (window, &x_widget, &y_widget);
380 if (coords == ATK_XY_SCREEN)
385 else if (coords == ATK_XY_WINDOW)
387 window = gdk_window_get_toplevel (window);
388 gdk_window_get_origin (window, &x_window, &y_window);
390 x = x - x_widget + x_window;
391 y = y - y_widget + y_window;
396 gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_WIDGET,
397 x, y, &buff_x, &buff_y);
398 gtk_text_view_get_visible_rect (view, &rect);
400 /* Clamp point to visible rectangle */
401 buff_x = CLAMP (buff_x, rect.x, rect.x + rect.width - 1);
402 buff_y = CLAMP (buff_y, rect.y, rect.y + rect.height - 1);
404 gtk_text_view_get_iter_at_location (view, &iter, buff_x, buff_y);
406 /* The iter at a location sometimes points to the next character.
407 * See bug 111031. We work around that
409 gtk_text_view_get_iter_location (view, &iter, &rect);
411 gtk_text_iter_backward_char (&iter);
412 return gtk_text_iter_get_offset (&iter);
416 gtk_text_view_accessible_get_character_extents (AtkText *text,
425 GtkTextBuffer *buffer;
428 GdkRectangle rectangle;
430 gint x_widget, y_widget, x_window, y_window;
432 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
436 view = GTK_TEXT_VIEW (widget);
437 buffer = gtk_text_view_get_buffer (view);
438 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
439 gtk_text_view_get_iter_location (view, &iter, &rectangle);
441 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
442 gdk_window_get_origin (window, &x_widget, &y_widget);
444 *height = rectangle.height;
445 *width = rectangle.width;
447 gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET,
448 rectangle.x, rectangle.y, x, y);
449 if (coords == ATK_XY_WINDOW)
451 window = gdk_window_get_toplevel (window);
452 gdk_window_get_origin (window, &x_window, &y_window);
453 *x += x_widget - x_window;
454 *y += y_widget - y_window;
456 else if (coords == ATK_XY_SCREEN)
470 static AtkAttributeSet *
471 gtk_text_view_accessible_get_run_attributes (AtkText *text,
477 GtkTextBuffer *buffer;
480 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
484 view = GTK_TEXT_VIEW (widget);
485 buffer = gtk_text_view_get_buffer (view);
487 return gail_misc_buffer_get_run_attributes (buffer, offset,
488 start_offset, end_offset);
491 static AtkAttributeSet *
492 add_text_attribute (AtkAttributeSet *attributes,
493 AtkTextAttribute attr,
498 at = g_new (AtkAttribute, 1);
500 at->name = g_strdup (atk_text_attribute_get_name (attr));
501 at->value = g_strdup (atk_text_attribute_get_value (attr, i));
503 return g_slist_prepend (attributes, at);
506 static AtkAttributeSet *
507 gtk_text_view_accessible_get_default_attributes (AtkText *text)
511 GtkTextAttributes *text_attrs;
512 AtkAttributeSet *attributes;
513 PangoFontDescription *font;
516 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
520 view = GTK_TEXT_VIEW (widget);
521 text_attrs = gtk_text_view_get_default_attributes (view);
525 font = text_attrs->font;
529 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STYLE,
530 pango_font_description_get_style (font));
532 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
533 pango_font_description_get_variant (font));
535 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
536 pango_font_description_get_stretch (font));
538 value = g_strdup (pango_font_description_get_family (font));
539 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value);
541 value = g_strdup_printf ("%d", pango_font_description_get_weight (font));
542 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value);
544 value = g_strdup_printf ("%i", pango_font_description_get_size (font) / PANGO_SCALE);
545 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_SIZE, value);
548 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION, text_attrs->justification);
549 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION, text_attrs->direction);
550 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE, text_attrs->wrap_mode);
551 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_EDITABLE, text_attrs->editable);
552 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE, text_attrs->invisible);
553 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, text_attrs->bg_full_height);
555 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
556 text_attrs->appearance.strikethrough);
557 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
558 text_attrs->appearance.underline);
560 value = g_strdup_printf ("%u,%u,%u",
561 text_attrs->appearance.bg_color.red,
562 text_attrs->appearance.bg_color.green,
563 text_attrs->appearance.bg_color.blue);
564 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
566 value = g_strdup_printf ("%u,%u,%u",
567 text_attrs->appearance.fg_color.red,
568 text_attrs->appearance.fg_color.green,
569 text_attrs->appearance.fg_color.blue);
570 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
572 value = g_strdup_printf ("%g", text_attrs->font_scale);
573 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_SCALE, value);
575 value = g_strdup ((gchar *)(text_attrs->language));
576 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, value);
578 value = g_strdup_printf ("%i", text_attrs->appearance.rise);
579 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_RISE, value);
581 value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
582 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
584 value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
585 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
587 value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
588 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
590 value = g_strdup_printf ("%i", text_attrs->indent);
591 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_INDENT, value);
593 value = g_strdup_printf ("%i", text_attrs->left_margin);
594 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, value);
596 value = g_strdup_printf ("%i", text_attrs->right_margin);
597 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
599 gtk_text_attributes_unref (text_attrs);
604 gtk_text_view_accessible_get_n_selections (AtkText *text)
607 GtkTextBuffer *buffer;
609 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
613 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
614 if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
621 gtk_text_view_accessible_get_selection (AtkText *atk_text,
628 GtkTextBuffer *buffer;
629 GtkTextIter start, end;
632 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
636 if (selection_num != 0)
639 view = GTK_TEXT_VIEW (widget);
640 buffer = gtk_text_view_get_buffer (view);
642 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
643 text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
647 *start_pos = gtk_text_iter_get_offset (&start);
648 *end_pos = gtk_text_iter_get_offset (&end);
654 gtk_text_view_accessible_add_selection (AtkText *text,
659 GtkTextBuffer *buffer;
660 GtkTextIter start, end;
662 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
666 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
668 if (!gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
670 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
671 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
672 gtk_text_buffer_select_range (buffer, &end, &start);
681 gtk_text_view_accessible_remove_selection (AtkText *text,
685 GtkTextBuffer *buffer;
688 GtkTextIter start, end;
690 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
694 if (selection_num != 0)
697 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
699 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
701 insert = gtk_text_buffer_get_insert (buffer);
702 gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
703 gtk_text_buffer_place_cursor (buffer, &iter);
711 gtk_text_view_accessible_set_selection (AtkText *text,
717 GtkTextBuffer *buffer;
718 GtkTextIter start, end;
720 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
724 if (selection_num != 0)
727 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
729 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
731 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
732 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
733 gtk_text_buffer_select_range (buffer, &end, &start);
742 atk_text_interface_init (AtkTextIface *iface)
744 iface->get_text = gtk_text_view_accessible_get_text;
745 iface->get_text_after_offset = gtk_text_view_accessible_get_text_after_offset;
746 iface->get_text_at_offset = gtk_text_view_accessible_get_text_at_offset;
747 iface->get_text_before_offset = gtk_text_view_accessible_get_text_before_offset;
748 iface->get_character_at_offset = gtk_text_view_accessible_get_character_at_offset;
749 iface->get_character_count = gtk_text_view_accessible_get_character_count;
750 iface->get_caret_offset = gtk_text_view_accessible_get_caret_offset;
751 iface->set_caret_offset = gtk_text_view_accessible_set_caret_offset;
752 iface->get_offset_at_point = gtk_text_view_accessible_get_offset_at_point;
753 iface->get_character_extents = gtk_text_view_accessible_get_character_extents;
754 iface->get_n_selections = gtk_text_view_accessible_get_n_selections;
755 iface->get_selection = gtk_text_view_accessible_get_selection;
756 iface->add_selection = gtk_text_view_accessible_add_selection;
757 iface->remove_selection = gtk_text_view_accessible_remove_selection;
758 iface->set_selection = gtk_text_view_accessible_set_selection;
759 iface->get_run_attributes = gtk_text_view_accessible_get_run_attributes;
760 iface->get_default_attributes = gtk_text_view_accessible_get_default_attributes;
763 /* atkeditabletext.h */
766 gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
767 AtkAttributeSet *attributes,
772 GtkTextBuffer *buffer;
782 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
786 view = GTK_TEXT_VIEW (widget);
787 if (!gtk_text_view_get_editable (view))
790 buffer = gtk_text_view_get_buffer (view);
792 if (attributes == NULL)
795 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
796 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
798 tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
800 for (l = attributes; l; l = l->next)
811 if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN)))
812 g_object_set (G_OBJECT (tag), "left_margin", atoi (value), NULL);
814 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN)))
815 g_object_set (G_OBJECT (tag), "right_margin", atoi (value), NULL);
817 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT)))
818 g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL);
820 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES)))
821 g_object_set (G_OBJECT (tag), "pixels_above_lines", atoi (value), NULL);
823 else if (!strcmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES)))
824 g_object_set (G_OBJECT (tag), "pixels_below_lines", atoi (value), NULL);
826 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP)))
827 g_object_set (G_OBJECT (tag), "pixels_inside_wrap", atoi (value), NULL);
829 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE)))
830 g_object_set (G_OBJECT (tag), "size", atoi (value), NULL);
832 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RISE)))
833 g_object_set (G_OBJECT (tag), "rise", atoi (value), NULL);
835 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WEIGHT)))
836 g_object_set (G_OBJECT (tag), "weight", atoi (value), NULL);
838 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT)))
840 g_object_set (G_OBJECT (tag), "bg_full_height",
841 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))),
845 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LANGUAGE)))
846 g_object_set (G_OBJECT (tag), "language", value, NULL);
848 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FAMILY_NAME)))
849 g_object_set (G_OBJECT (tag), "family", value, NULL);
851 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_EDITABLE)))
853 g_object_set (G_OBJECT (tag), "editable",
854 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
858 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INVISIBLE)))
860 g_object_set (G_OBJECT (tag), "invisible",
861 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
865 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_UNDERLINE)))
867 for (j = 0; j < 3; j++)
869 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, j)))
871 g_object_set (G_OBJECT (tag), "underline", j, NULL);
877 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRIKETHROUGH)))
879 g_object_set (G_OBJECT (tag), "strikethrough",
880 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0))),
884 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_COLOR)))
886 RGB_vals = g_strsplit (value, ",", 3);
887 color = g_malloc (sizeof (GdkColor));
888 color->red = atoi (RGB_vals[0]);
889 color->green = atoi (RGB_vals[1]);
890 color->blue = atoi (RGB_vals[2]);
891 g_object_set (G_OBJECT (tag), "background_gdk", color, NULL);
894 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR)))
896 RGB_vals = g_strsplit (value, ",", 3);
897 color = g_malloc (sizeof (GdkColor));
898 color->red = atoi (RGB_vals[0]);
899 color->green = atoi (RGB_vals[1]);
900 color->blue = atoi (RGB_vals[2]);
901 g_object_set (G_OBJECT (tag), "foreground_gdk", color, NULL);
904 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH)))
906 for (j = 0; j < 9; j++)
908 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, j)))
910 g_object_set (G_OBJECT (tag), "stretch", j, NULL);
916 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_JUSTIFICATION)))
918 for (j = 0; j < 4; j++)
920 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, j)))
922 g_object_set (G_OBJECT (tag), "justification", j, NULL);
928 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_DIRECTION)))
930 for (j = 0; j < 3; j++)
932 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, j)))
934 g_object_set (G_OBJECT (tag), "direction", j, NULL);
940 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_VARIANT)))
942 for (j = 0; j < 2; j++)
944 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, j)))
946 g_object_set (G_OBJECT (tag), "variant", j, NULL);
952 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WRAP_MODE)))
954 for (j = 0; j < 3; j++)
956 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j)))
958 g_object_set (G_OBJECT (tag), "wrap_mode", j, NULL);
964 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STYLE)))
966 for (j = 0; j < 3; j++)
968 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, j)))
970 g_object_set (G_OBJECT (tag), "style", j, NULL);
980 gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
986 gtk_text_view_accessible_set_text_contents (AtkEditableText *text,
991 GtkTextBuffer *buffer;
993 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
997 view = GTK_TEXT_VIEW (widget);
998 if (!gtk_text_view_get_editable (view))
1001 buffer = gtk_text_view_get_buffer (view);
1002 gtk_text_buffer_set_text (buffer, string, -1);
1006 gtk_text_view_accessible_insert_text (AtkEditableText *text,
1007 const gchar *string,
1013 GtkTextBuffer *buffer;
1016 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1020 view = GTK_TEXT_VIEW (widget);
1021 if (!gtk_text_view_get_editable (view))
1024 buffer = gtk_text_view_get_buffer (view);
1025 gtk_text_buffer_get_iter_at_offset (buffer, &iter, *position);
1026 gtk_text_buffer_insert (buffer, &iter, string, length);
1030 gtk_text_view_accessible_copy_text (AtkEditableText *text,
1035 GtkTextBuffer *buffer;
1036 GtkTextIter start, end;
1038 GtkClipboard *clipboard;
1040 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1044 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1046 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1047 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1048 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1050 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1051 gtk_clipboard_set_text (clipboard, str, -1);
1055 gtk_text_view_accessible_cut_text (AtkEditableText *text,
1061 GtkTextBuffer *buffer;
1062 GtkTextIter start, end;
1064 GtkClipboard *clipboard;
1066 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1070 view = GTK_TEXT_VIEW (widget);
1071 if (!gtk_text_view_get_editable (view))
1073 buffer = gtk_text_view_get_buffer (view);
1075 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1076 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1077 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1078 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1079 gtk_clipboard_set_text (clipboard, str, -1);
1080 gtk_text_buffer_delete (buffer, &start, &end);
1084 gtk_text_view_accessible_delete_text (AtkEditableText *text,
1090 GtkTextBuffer *buffer;
1091 GtkTextIter start_itr;
1092 GtkTextIter end_itr;
1094 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1098 view = GTK_TEXT_VIEW (widget);
1099 if (!gtk_text_view_get_editable (view))
1101 buffer = gtk_text_view_get_buffer (view);
1103 gtk_text_buffer_get_iter_at_offset (buffer, &start_itr, start_pos);
1104 gtk_text_buffer_get_iter_at_offset (buffer, &end_itr, end_pos);
1105 gtk_text_buffer_delete (buffer, &start_itr, &end_itr);
1110 GtkTextBuffer* buffer;
1115 paste_received (GtkClipboard *clipboard,
1119 PasteData* paste = data;
1120 GtkTextIter pos_itr;
1124 gtk_text_buffer_get_iter_at_offset (paste->buffer, &pos_itr, paste->position);
1125 gtk_text_buffer_insert (paste->buffer, &pos_itr, text, -1);
1128 g_object_unref (paste->buffer);
1132 gtk_text_view_accessible_paste_text (AtkEditableText *text,
1137 GtkTextBuffer *buffer;
1139 GtkClipboard *clipboard;
1141 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1145 view = GTK_TEXT_VIEW (widget);
1146 if (!gtk_text_view_get_editable (view))
1148 buffer = gtk_text_view_get_buffer (view);
1150 paste.buffer = buffer;
1151 paste.position = position;
1153 g_object_ref (paste.buffer);
1154 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1155 gtk_clipboard_request_text (clipboard, paste_received, &paste);
1159 atk_editable_text_interface_init (AtkEditableTextIface *iface)
1161 iface->set_text_contents = gtk_text_view_accessible_set_text_contents;
1162 iface->insert_text = gtk_text_view_accessible_insert_text;
1163 iface->copy_text = gtk_text_view_accessible_copy_text;
1164 iface->cut_text = gtk_text_view_accessible_cut_text;
1165 iface->delete_text = gtk_text_view_accessible_delete_text;
1166 iface->paste_text = gtk_text_view_accessible_paste_text;
1167 iface->set_run_attributes = gtk_text_view_accessible_set_run_attributes;
1173 insert_text_cb (GtkTextBuffer *buffer,
1179 GtkTextView *view = data;
1180 GtkTextViewAccessible *accessible;
1184 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
1186 accessible->signal_name = "text_changed::insert";
1187 position = gtk_text_iter_get_offset (iter);
1188 length = g_utf8_strlen (text, len);
1190 if (accessible->length == 0)
1192 accessible->position = position;
1193 accessible->length = length;
1195 else if (accessible->position + accessible->length == position)
1197 accessible->length += length;
1202 * We have a non-contiguous insert so report what we have
1204 if (accessible->insert_notify_handler)
1206 g_source_remove (accessible->insert_notify_handler);
1208 accessible->insert_notify_handler = 0;
1209 insert_idle_handler (accessible);
1210 accessible->position = position;
1211 accessible->length = length;
1216 delete_range_cb (GtkTextBuffer *buffer,
1221 GtkTextView *text = data;
1222 GtkTextViewAccessible *accessible;
1227 offset = gtk_text_iter_get_offset (start);
1228 length = gtk_text_iter_get_offset (end) - offset;
1230 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
1231 if (accessible->insert_notify_handler)
1233 g_source_remove (accessible->insert_notify_handler);
1234 accessible->insert_notify_handler = 0;
1235 if (accessible->position == offset &&
1236 accessible->length == length)
1239 * Do not bother with insert and delete notifications
1241 accessible->signal_name = NULL;
1242 accessible->position = 0;
1243 accessible->length = 0;
1247 insert_idle_handler (accessible);
1249 g_signal_emit_by_name (accessible, "text_changed::delete", offset, length);
1253 get_selection_bound (GtkTextBuffer *buffer)
1258 bound = gtk_text_buffer_get_selection_bound (buffer);
1259 gtk_text_buffer_get_iter_at_mark (buffer, &iter, bound);
1260 return gtk_text_iter_get_offset (&iter);
1264 emit_text_caret_moved (GtkTextViewAccessible *accessible,
1268 * If we have text which has been inserted notify the user
1270 if (accessible->insert_notify_handler)
1272 g_source_remove (accessible->insert_notify_handler);
1273 accessible->insert_notify_handler = 0;
1274 insert_idle_handler (accessible);
1277 if (offset != accessible->previous_insert_offset)
1280 * If the caret position has not changed then don't bother notifying
1282 * When mouse click is used to change caret position, notification
1283 * is received on button down and button up.
1285 g_signal_emit_by_name (accessible, "text_caret_moved", offset);
1286 accessible->previous_insert_offset = offset;
1291 mark_set_cb (GtkTextBuffer *buffer,
1292 GtkTextIter *location,
1296 GtkTextView *text = data;
1297 GtkTextViewAccessible *accessible;
1298 const char *mark_name;
1300 mark_name = gtk_text_mark_get_name (mark);
1302 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
1305 * Only generate the signal for the "insert" mark, which
1306 * represents the cursor.
1308 if (g_strcmp0 (mark_name, "insert") == 0)
1310 gint insert_offset, selection_bound;
1311 gboolean selection_changed;
1313 insert_offset = gtk_text_iter_get_offset (location);
1315 selection_bound = get_selection_bound (buffer);
1316 if (selection_bound != insert_offset)
1318 if (selection_bound != accessible->previous_selection_bound ||
1319 insert_offset != accessible->previous_insert_offset)
1320 selection_changed = TRUE;
1322 selection_changed = FALSE;
1324 else if (accessible->previous_selection_bound != accessible->previous_insert_offset)
1325 selection_changed = TRUE;
1327 selection_changed = FALSE;
1329 emit_text_caret_moved (accessible, insert_offset);
1331 * insert and selection_bound marks are different to a selection
1334 if (selection_changed)
1335 g_signal_emit_by_name (accessible, "text_selection_changed");
1336 accessible->previous_selection_bound = selection_bound;
1341 changed_cb (GtkTextBuffer *buffer,
1344 GtkTextView *text = data;
1345 GtkTextViewAccessible *accessible;
1347 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
1348 if (accessible->signal_name)
1350 if (!accessible->insert_notify_handler)
1352 accessible->insert_notify_handler = gdk_threads_add_idle (insert_idle_handler, accessible);
1356 emit_text_caret_moved (accessible, get_insert_offset (buffer));
1357 accessible->previous_selection_bound = get_selection_bound (buffer);
1361 insert_idle_handler (gpointer data)
1363 GtkTextViewAccessible *accessible = data;
1365 GtkTextBuffer *buffer;
1367 g_signal_emit_by_name (data,
1368 accessible->signal_name,
1369 accessible->position,
1370 accessible->length);
1371 accessible->signal_name = NULL;
1372 accessible->position = 0;
1373 accessible->length = 0;
1375 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
1376 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1377 if (accessible->insert_notify_handler)
1380 * If called from idle handler notify caret moved
1382 accessible->insert_notify_handler = 0;
1383 emit_text_caret_moved (accessible, get_insert_offset (buffer));
1384 accessible->previous_selection_bound = get_selection_bound (buffer);
1391 gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable)
1394 GtkTextBuffer *buffer;
1395 gint n_mime_types = 0;
1397 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1401 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1405 gboolean advertises_plaintext = FALSE;
1408 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1409 for (i = 0; i < n_mime_types-1; ++i)
1410 if (!strcmp ("text/plain", gdk_atom_name (atoms[i])))
1411 advertises_plaintext = TRUE;
1412 if (!advertises_plaintext)
1416 return n_mime_types;
1419 static const gchar *
1420 gail_streamable_content_get_mime_type (AtkStreamableContent *streamable,
1424 GtkTextBuffer *buffer;
1426 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1430 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1433 gint n_mime_types = 0;
1436 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1437 if (i < n_mime_types)
1438 return gdk_atom_name (atoms [i]);
1439 else if (i == n_mime_types)
1440 return "text/plain";
1447 gail_streamable_content_get_stream (AtkStreamableContent *streamable,
1448 const gchar *mime_type)
1451 GtkTextBuffer *buffer;
1452 gint i, n_mime_types = 0;
1455 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1459 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1463 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1465 for (i = 0; i < n_mime_types; ++i)
1467 if (!strcmp ("text/plain", mime_type) ||
1468 !strcmp (gdk_atom_name (atoms[i]), mime_type))
1474 GtkTextIter start, end;
1475 GIOChannel *gio = NULL;
1478 gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
1479 gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
1480 if (!strcmp ("text/plain", mime_type))
1482 cbuf = (guint8*) gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1483 len = strlen ((const char *) cbuf);
1487 cbuf = gtk_text_buffer_serialize (buffer, buffer, atoms[i], &start, &end, &len);
1489 g_snprintf (tname, 20, "streamXXXXXX");
1490 fd = g_mkstemp (tname);
1491 gio = g_io_channel_unix_new (fd);
1492 g_io_channel_set_encoding (gio, NULL, &err);
1494 g_io_channel_write_chars (gio, (const char *) cbuf, (gssize) len, &written, &err);
1496 g_message ("%s", err->message);
1498 g_io_channel_seek_position (gio, 0, G_SEEK_SET, &err);
1500 g_message ("%s", err->message);
1502 g_io_channel_flush (gio, &err);
1504 g_message ("%s", err->message);
1507 g_message ("<error writing to stream [%s]>", tname);
1510 /* make sure the file is removed on unref of the giochannel */
1523 atk_streamable_content_interface_init (AtkStreamableContentIface *iface)
1525 iface->get_n_mime_types = gail_streamable_content_get_n_mime_types;
1526 iface->get_mime_type = gail_streamable_content_get_mime_type;
1527 iface->get_stream = gail_streamable_content_get_stream;