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 GTK_WIDGET_ACCESSIBLE_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 GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
133 gobject_class->finalize = gtk_text_view_accessible_finalize;
135 class->ref_state_set = gtk_text_view_accessible_ref_state_set;
136 class->initialize = gtk_text_view_accessible_initialize;
138 widget_class->notify_gtk = gtk_text_view_accessible_notify_gtk;
142 gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
144 accessible->signal_name = NULL;
145 accessible->previous_insert_offset = -1;
146 accessible->previous_selection_bound = -1;
147 accessible->insert_notify_handler = 0;
151 setup_buffer (GtkTextView *view,
152 GtkTextViewAccessible *accessible)
154 GtkTextBuffer *buffer;
156 buffer = gtk_text_view_get_buffer (view);
158 /* Set up signal callbacks */
159 g_signal_connect_data (buffer, "insert-text",
160 (GCallback) insert_text_cb, view, NULL, 0);
161 g_signal_connect_data (buffer, "delete-range",
162 (GCallback) delete_range_cb, view, NULL, 0);
163 g_signal_connect_data (buffer, "mark-set",
164 (GCallback) mark_set_cb, view, NULL, 0);
165 g_signal_connect_data (buffer, "changed",
166 (GCallback) changed_cb, view, NULL, 0);
171 gtk_text_view_accessible_get_text (AtkText *text,
176 GtkTextBuffer *buffer;
177 GtkTextIter start, end;
180 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
184 view = GTK_TEXT_VIEW (widget);
185 buffer = gtk_text_view_get_buffer (view);
186 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
187 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
189 return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
193 gtk_text_view_accessible_get_text_after_offset (AtkText *text,
195 AtkTextBoundary boundary_type,
200 GtkTextBuffer *buffer;
202 GtkTextIter start, end;
204 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
208 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
209 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
210 _gtk_text_buffer_get_text_after (buffer, boundary_type,
212 *start_offset = gtk_text_iter_get_offset (&start);
213 *end_offset = gtk_text_iter_get_offset (&end);
214 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
218 gtk_text_view_accessible_get_text_at_offset (AtkText *text,
220 AtkTextBoundary boundary_type,
225 GtkTextBuffer *buffer;
227 GtkTextIter start, end;
229 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
233 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
234 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
235 _gtk_text_buffer_get_text_at (buffer, boundary_type,
237 *start_offset = gtk_text_iter_get_offset (&start);
238 *end_offset = gtk_text_iter_get_offset (&end);
239 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
243 gtk_text_view_accessible_get_text_before_offset (AtkText *text,
245 AtkTextBoundary boundary_type,
250 GtkTextBuffer *buffer;
252 GtkTextIter start, end;
254 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
258 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
259 gtk_text_buffer_get_iter_at_offset (buffer, &pos, offset);
260 _gtk_text_buffer_get_text_before (buffer, boundary_type,
262 *start_offset = gtk_text_iter_get_offset (&start);
263 *end_offset = gtk_text_iter_get_offset (&end);
264 return gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
268 gtk_text_view_accessible_get_character_at_offset (AtkText *text,
272 GtkTextIter start, end;
273 GtkTextBuffer *buffer;
277 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
281 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
282 if (offset >= gtk_text_buffer_get_char_count (buffer))
285 gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
287 gtk_text_iter_forward_char (&end);
288 string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
289 unichar = g_utf8_get_char (string);
296 gtk_text_view_accessible_get_character_count (AtkText *text)
299 GtkTextBuffer *buffer;
301 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
305 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
306 return gtk_text_buffer_get_char_count (buffer);
310 get_insert_offset (GtkTextBuffer *buffer)
315 insert = gtk_text_buffer_get_insert (buffer);
316 gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
317 return gtk_text_iter_get_offset (&iter);
321 gtk_text_view_accessible_get_caret_offset (AtkText *text)
324 GtkTextBuffer *buffer;
326 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
330 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
331 return get_insert_offset (buffer);
335 gtk_text_view_accessible_set_caret_offset (AtkText *text,
340 GtkTextBuffer *buffer;
343 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
347 view = GTK_TEXT_VIEW (widget);
348 buffer = gtk_text_view_get_buffer (view);
350 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
351 gtk_text_buffer_place_cursor (buffer, &iter);
352 gtk_text_view_scroll_to_iter (view, &iter, 0, FALSE, 0, 0);
358 gtk_text_view_accessible_get_offset_at_point (AtkText *text,
365 gint x_widget, y_widget, x_window, y_window, buff_x, buff_y;
370 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
374 view = GTK_TEXT_VIEW (widget);
375 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
376 gdk_window_get_origin (window, &x_widget, &y_widget);
378 if (coords == ATK_XY_SCREEN)
383 else if (coords == ATK_XY_WINDOW)
385 window = gdk_window_get_toplevel (window);
386 gdk_window_get_origin (window, &x_window, &y_window);
388 x = x - x_widget + x_window;
389 y = y - y_widget + y_window;
394 gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_WIDGET,
395 x, y, &buff_x, &buff_y);
396 gtk_text_view_get_visible_rect (view, &rect);
398 /* Clamp point to visible rectangle */
399 buff_x = CLAMP (buff_x, rect.x, rect.x + rect.width - 1);
400 buff_y = CLAMP (buff_y, rect.y, rect.y + rect.height - 1);
402 gtk_text_view_get_iter_at_location (view, &iter, buff_x, buff_y);
404 /* The iter at a location sometimes points to the next character.
405 * See bug 111031. We work around that
407 gtk_text_view_get_iter_location (view, &iter, &rect);
409 gtk_text_iter_backward_char (&iter);
410 return gtk_text_iter_get_offset (&iter);
414 gtk_text_view_accessible_get_character_extents (AtkText *text,
423 GtkTextBuffer *buffer;
426 GdkRectangle rectangle;
428 gint x_widget, y_widget, x_window, y_window;
430 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
434 view = GTK_TEXT_VIEW (widget);
435 buffer = gtk_text_view_get_buffer (view);
436 gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
437 gtk_text_view_get_iter_location (view, &iter, &rectangle);
439 window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET);
440 gdk_window_get_origin (window, &x_widget, &y_widget);
442 *height = rectangle.height;
443 *width = rectangle.width;
445 gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET,
446 rectangle.x, rectangle.y, x, y);
447 if (coords == ATK_XY_WINDOW)
449 window = gdk_window_get_toplevel (window);
450 gdk_window_get_origin (window, &x_window, &y_window);
451 *x += x_widget - x_window;
452 *y += y_widget - y_window;
454 else if (coords == ATK_XY_SCREEN)
468 static AtkAttributeSet *
469 gtk_text_view_accessible_get_run_attributes (AtkText *text,
475 GtkTextBuffer *buffer;
478 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
482 view = GTK_TEXT_VIEW (widget);
483 buffer = gtk_text_view_get_buffer (view);
485 return gail_misc_buffer_get_run_attributes (buffer, offset,
486 start_offset, end_offset);
489 static AtkAttributeSet *
490 add_text_attribute (AtkAttributeSet *attributes,
491 AtkTextAttribute attr,
496 at = g_new (AtkAttribute, 1);
498 at->name = g_strdup (atk_text_attribute_get_name (attr));
499 at->value = g_strdup (atk_text_attribute_get_value (attr, i));
501 return g_slist_prepend (attributes, at);
504 static AtkAttributeSet *
505 gtk_text_view_accessible_get_default_attributes (AtkText *text)
509 GtkTextAttributes *text_attrs;
510 AtkAttributeSet *attributes;
511 PangoFontDescription *font;
514 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
518 view = GTK_TEXT_VIEW (widget);
519 text_attrs = gtk_text_view_get_default_attributes (view);
523 font = text_attrs->font;
527 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STYLE,
528 pango_font_description_get_style (font));
530 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_VARIANT,
531 pango_font_description_get_variant (font));
533 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STRETCH,
534 pango_font_description_get_stretch (font));
536 value = g_strdup (pango_font_description_get_family (font));
537 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_FAMILY_NAME, value);
539 value = g_strdup_printf ("%d", pango_font_description_get_weight (font));
540 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_WEIGHT, value);
542 value = g_strdup_printf ("%i", pango_font_description_get_size (font) / PANGO_SCALE);
543 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_SIZE, value);
546 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_JUSTIFICATION, text_attrs->justification);
547 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_DIRECTION, text_attrs->direction);
548 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_WRAP_MODE, text_attrs->wrap_mode);
549 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_EDITABLE, text_attrs->editable);
550 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_INVISIBLE, text_attrs->invisible);
551 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_BG_FULL_HEIGHT, text_attrs->bg_full_height);
553 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_STRIKETHROUGH,
554 text_attrs->appearance.strikethrough);
555 attributes = add_text_attribute (attributes, ATK_TEXT_ATTR_UNDERLINE,
556 text_attrs->appearance.underline);
558 value = g_strdup_printf ("%u,%u,%u",
559 text_attrs->appearance.bg_color.red,
560 text_attrs->appearance.bg_color.green,
561 text_attrs->appearance.bg_color.blue);
562 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
564 value = g_strdup_printf ("%u,%u,%u",
565 text_attrs->appearance.fg_color.red,
566 text_attrs->appearance.fg_color.green,
567 text_attrs->appearance.fg_color.blue);
568 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
570 value = g_strdup_printf ("%g", text_attrs->font_scale);
571 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_SCALE, value);
573 value = g_strdup ((gchar *)(text_attrs->language));
574 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_LANGUAGE, value);
576 value = g_strdup_printf ("%i", text_attrs->appearance.rise);
577 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_RISE, value);
579 value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
580 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP, value);
582 value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
583 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_BELOW_LINES, value);
585 value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
586 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_PIXELS_ABOVE_LINES, value);
588 value = g_strdup_printf ("%i", text_attrs->indent);
589 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_INDENT, value);
591 value = g_strdup_printf ("%i", text_attrs->left_margin);
592 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_LEFT_MARGIN, value);
594 value = g_strdup_printf ("%i", text_attrs->right_margin);
595 attributes = gail_misc_add_attribute (attributes, ATK_TEXT_ATTR_RIGHT_MARGIN, value);
597 gtk_text_attributes_unref (text_attrs);
602 gtk_text_view_accessible_get_n_selections (AtkText *text)
605 GtkTextBuffer *buffer;
607 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
611 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
612 if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
619 gtk_text_view_accessible_get_selection (AtkText *atk_text,
626 GtkTextBuffer *buffer;
627 GtkTextIter start, end;
630 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (atk_text));
634 if (selection_num != 0)
637 view = GTK_TEXT_VIEW (widget);
638 buffer = gtk_text_view_get_buffer (view);
640 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
641 text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
645 *start_pos = gtk_text_iter_get_offset (&start);
646 *end_pos = gtk_text_iter_get_offset (&end);
652 gtk_text_view_accessible_add_selection (AtkText *text,
657 GtkTextBuffer *buffer;
658 GtkTextIter start, end;
660 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
664 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
666 if (!gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
668 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
669 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
670 gtk_text_buffer_select_range (buffer, &end, &start);
679 gtk_text_view_accessible_remove_selection (AtkText *text,
683 GtkTextBuffer *buffer;
686 GtkTextIter start, end;
688 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
692 if (selection_num != 0)
695 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
697 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
699 insert = gtk_text_buffer_get_insert (buffer);
700 gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
701 gtk_text_buffer_place_cursor (buffer, &iter);
709 gtk_text_view_accessible_set_selection (AtkText *text,
715 GtkTextBuffer *buffer;
716 GtkTextIter start, end;
718 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
722 if (selection_num != 0)
725 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
727 if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
729 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
730 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
731 gtk_text_buffer_select_range (buffer, &end, &start);
740 atk_text_interface_init (AtkTextIface *iface)
742 iface->get_text = gtk_text_view_accessible_get_text;
743 iface->get_text_after_offset = gtk_text_view_accessible_get_text_after_offset;
744 iface->get_text_at_offset = gtk_text_view_accessible_get_text_at_offset;
745 iface->get_text_before_offset = gtk_text_view_accessible_get_text_before_offset;
746 iface->get_character_at_offset = gtk_text_view_accessible_get_character_at_offset;
747 iface->get_character_count = gtk_text_view_accessible_get_character_count;
748 iface->get_caret_offset = gtk_text_view_accessible_get_caret_offset;
749 iface->set_caret_offset = gtk_text_view_accessible_set_caret_offset;
750 iface->get_offset_at_point = gtk_text_view_accessible_get_offset_at_point;
751 iface->get_character_extents = gtk_text_view_accessible_get_character_extents;
752 iface->get_n_selections = gtk_text_view_accessible_get_n_selections;
753 iface->get_selection = gtk_text_view_accessible_get_selection;
754 iface->add_selection = gtk_text_view_accessible_add_selection;
755 iface->remove_selection = gtk_text_view_accessible_remove_selection;
756 iface->set_selection = gtk_text_view_accessible_set_selection;
757 iface->get_run_attributes = gtk_text_view_accessible_get_run_attributes;
758 iface->get_default_attributes = gtk_text_view_accessible_get_default_attributes;
761 /* atkeditabletext.h */
764 gtk_text_view_accessible_set_run_attributes (AtkEditableText *text,
765 AtkAttributeSet *attributes,
770 GtkTextBuffer *buffer;
780 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
784 view = GTK_TEXT_VIEW (widget);
785 if (!gtk_text_view_get_editable (view))
788 buffer = gtk_text_view_get_buffer (view);
790 if (attributes == NULL)
793 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset);
794 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset);
796 tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
798 for (l = attributes; l; l = l->next)
809 if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN)))
810 g_object_set (G_OBJECT (tag), "left_margin", atoi (value), NULL);
812 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN)))
813 g_object_set (G_OBJECT (tag), "right_margin", atoi (value), NULL);
815 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT)))
816 g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL);
818 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES)))
819 g_object_set (G_OBJECT (tag), "pixels_above_lines", atoi (value), NULL);
821 else if (!strcmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES)))
822 g_object_set (G_OBJECT (tag), "pixels_below_lines", atoi (value), NULL);
824 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP)))
825 g_object_set (G_OBJECT (tag), "pixels_inside_wrap", atoi (value), NULL);
827 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE)))
828 g_object_set (G_OBJECT (tag), "size", atoi (value), NULL);
830 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RISE)))
831 g_object_set (G_OBJECT (tag), "rise", atoi (value), NULL);
833 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WEIGHT)))
834 g_object_set (G_OBJECT (tag), "weight", atoi (value), NULL);
836 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT)))
838 g_object_set (G_OBJECT (tag), "bg_full_height",
839 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))),
843 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LANGUAGE)))
844 g_object_set (G_OBJECT (tag), "language", value, NULL);
846 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FAMILY_NAME)))
847 g_object_set (G_OBJECT (tag), "family", value, NULL);
849 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_EDITABLE)))
851 g_object_set (G_OBJECT (tag), "editable",
852 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
856 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INVISIBLE)))
858 g_object_set (G_OBJECT (tag), "invisible",
859 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))),
863 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_UNDERLINE)))
865 for (j = 0; j < 3; j++)
867 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, j)))
869 g_object_set (G_OBJECT (tag), "underline", j, NULL);
875 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRIKETHROUGH)))
877 g_object_set (G_OBJECT (tag), "strikethrough",
878 (strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0))),
882 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_COLOR)))
884 RGB_vals = g_strsplit (value, ",", 3);
885 color = g_malloc (sizeof (GdkColor));
886 color->red = atoi (RGB_vals[0]);
887 color->green = atoi (RGB_vals[1]);
888 color->blue = atoi (RGB_vals[2]);
889 g_object_set (G_OBJECT (tag), "background_gdk", color, NULL);
892 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR)))
894 RGB_vals = g_strsplit (value, ",", 3);
895 color = g_malloc (sizeof (GdkColor));
896 color->red = atoi (RGB_vals[0]);
897 color->green = atoi (RGB_vals[1]);
898 color->blue = atoi (RGB_vals[2]);
899 g_object_set (G_OBJECT (tag), "foreground_gdk", color, NULL);
902 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH)))
904 for (j = 0; j < 9; j++)
906 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, j)))
908 g_object_set (G_OBJECT (tag), "stretch", j, NULL);
914 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_JUSTIFICATION)))
916 for (j = 0; j < 4; j++)
918 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, j)))
920 g_object_set (G_OBJECT (tag), "justification", j, NULL);
926 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_DIRECTION)))
928 for (j = 0; j < 3; j++)
930 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, j)))
932 g_object_set (G_OBJECT (tag), "direction", j, NULL);
938 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_VARIANT)))
940 for (j = 0; j < 2; j++)
942 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, j)))
944 g_object_set (G_OBJECT (tag), "variant", j, NULL);
950 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WRAP_MODE)))
952 for (j = 0; j < 3; j++)
954 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j)))
956 g_object_set (G_OBJECT (tag), "wrap_mode", j, NULL);
962 else if (!strcmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STYLE)))
964 for (j = 0; j < 3; j++)
966 if (!strcmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, j)))
968 g_object_set (G_OBJECT (tag), "style", j, NULL);
978 gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
984 gtk_text_view_accessible_set_text_contents (AtkEditableText *text,
989 GtkTextBuffer *buffer;
991 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
995 view = GTK_TEXT_VIEW (widget);
996 if (!gtk_text_view_get_editable (view))
999 buffer = gtk_text_view_get_buffer (view);
1000 gtk_text_buffer_set_text (buffer, string, -1);
1004 gtk_text_view_accessible_insert_text (AtkEditableText *text,
1005 const gchar *string,
1011 GtkTextBuffer *buffer;
1014 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1018 view = GTK_TEXT_VIEW (widget);
1019 if (!gtk_text_view_get_editable (view))
1022 buffer = gtk_text_view_get_buffer (view);
1023 gtk_text_buffer_get_iter_at_offset (buffer, &iter, *position);
1024 gtk_text_buffer_insert (buffer, &iter, string, length);
1028 gtk_text_view_accessible_copy_text (AtkEditableText *text,
1033 GtkTextBuffer *buffer;
1034 GtkTextIter start, end;
1036 GtkClipboard *clipboard;
1038 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1042 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1044 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1045 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1046 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1048 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1049 gtk_clipboard_set_text (clipboard, str, -1);
1053 gtk_text_view_accessible_cut_text (AtkEditableText *text,
1059 GtkTextBuffer *buffer;
1060 GtkTextIter start, end;
1062 GtkClipboard *clipboard;
1064 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1068 view = GTK_TEXT_VIEW (widget);
1069 if (!gtk_text_view_get_editable (view))
1071 buffer = gtk_text_view_get_buffer (view);
1073 gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
1074 gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
1075 str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1076 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1077 gtk_clipboard_set_text (clipboard, str, -1);
1078 gtk_text_buffer_delete (buffer, &start, &end);
1082 gtk_text_view_accessible_delete_text (AtkEditableText *text,
1088 GtkTextBuffer *buffer;
1089 GtkTextIter start_itr;
1090 GtkTextIter end_itr;
1092 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1096 view = GTK_TEXT_VIEW (widget);
1097 if (!gtk_text_view_get_editable (view))
1099 buffer = gtk_text_view_get_buffer (view);
1101 gtk_text_buffer_get_iter_at_offset (buffer, &start_itr, start_pos);
1102 gtk_text_buffer_get_iter_at_offset (buffer, &end_itr, end_pos);
1103 gtk_text_buffer_delete (buffer, &start_itr, &end_itr);
1108 GtkTextBuffer* buffer;
1113 paste_received (GtkClipboard *clipboard,
1117 PasteData* paste = data;
1118 GtkTextIter pos_itr;
1122 gtk_text_buffer_get_iter_at_offset (paste->buffer, &pos_itr, paste->position);
1123 gtk_text_buffer_insert (paste->buffer, &pos_itr, text, -1);
1126 g_object_unref (paste->buffer);
1130 gtk_text_view_accessible_paste_text (AtkEditableText *text,
1135 GtkTextBuffer *buffer;
1137 GtkClipboard *clipboard;
1139 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
1143 view = GTK_TEXT_VIEW (widget);
1144 if (!gtk_text_view_get_editable (view))
1146 buffer = gtk_text_view_get_buffer (view);
1148 paste.buffer = buffer;
1149 paste.position = position;
1151 g_object_ref (paste.buffer);
1152 clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
1153 gtk_clipboard_request_text (clipboard, paste_received, &paste);
1157 atk_editable_text_interface_init (AtkEditableTextIface *iface)
1159 iface->set_text_contents = gtk_text_view_accessible_set_text_contents;
1160 iface->insert_text = gtk_text_view_accessible_insert_text;
1161 iface->copy_text = gtk_text_view_accessible_copy_text;
1162 iface->cut_text = gtk_text_view_accessible_cut_text;
1163 iface->delete_text = gtk_text_view_accessible_delete_text;
1164 iface->paste_text = gtk_text_view_accessible_paste_text;
1165 iface->set_run_attributes = gtk_text_view_accessible_set_run_attributes;
1171 insert_text_cb (GtkTextBuffer *buffer,
1177 GtkTextView *view = data;
1178 GtkTextViewAccessible *accessible;
1182 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
1184 accessible->signal_name = "text_changed::insert";
1185 position = gtk_text_iter_get_offset (iter);
1186 length = g_utf8_strlen (text, len);
1188 if (accessible->length == 0)
1190 accessible->position = position;
1191 accessible->length = length;
1193 else if (accessible->position + accessible->length == position)
1195 accessible->length += length;
1200 * We have a non-contiguous insert so report what we have
1202 if (accessible->insert_notify_handler)
1204 g_source_remove (accessible->insert_notify_handler);
1206 accessible->insert_notify_handler = 0;
1207 insert_idle_handler (accessible);
1208 accessible->position = position;
1209 accessible->length = length;
1214 delete_range_cb (GtkTextBuffer *buffer,
1219 GtkTextView *text = data;
1220 GtkTextViewAccessible *accessible;
1225 offset = gtk_text_iter_get_offset (start);
1226 length = gtk_text_iter_get_offset (end) - offset;
1228 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
1229 if (accessible->insert_notify_handler)
1231 g_source_remove (accessible->insert_notify_handler);
1232 accessible->insert_notify_handler = 0;
1233 if (accessible->position == offset &&
1234 accessible->length == length)
1237 * Do not bother with insert and delete notifications
1239 accessible->signal_name = NULL;
1240 accessible->position = 0;
1241 accessible->length = 0;
1245 insert_idle_handler (accessible);
1247 g_signal_emit_by_name (accessible, "text_changed::delete", offset, length);
1251 get_selection_bound (GtkTextBuffer *buffer)
1256 bound = gtk_text_buffer_get_selection_bound (buffer);
1257 gtk_text_buffer_get_iter_at_mark (buffer, &iter, bound);
1258 return gtk_text_iter_get_offset (&iter);
1262 emit_text_caret_moved (GtkTextViewAccessible *accessible,
1266 * If we have text which has been inserted notify the user
1268 if (accessible->insert_notify_handler)
1270 g_source_remove (accessible->insert_notify_handler);
1271 accessible->insert_notify_handler = 0;
1272 insert_idle_handler (accessible);
1275 if (offset != accessible->previous_insert_offset)
1278 * If the caret position has not changed then don't bother notifying
1280 * When mouse click is used to change caret position, notification
1281 * is received on button down and button up.
1283 g_signal_emit_by_name (accessible, "text_caret_moved", offset);
1284 accessible->previous_insert_offset = offset;
1289 mark_set_cb (GtkTextBuffer *buffer,
1290 GtkTextIter *location,
1294 GtkTextView *text = data;
1295 GtkTextViewAccessible *accessible;
1296 const char *mark_name;
1298 mark_name = gtk_text_mark_get_name (mark);
1300 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
1303 * Only generate the signal for the "insert" mark, which
1304 * represents the cursor.
1306 if (g_strcmp0 (mark_name, "insert") == 0)
1308 gint insert_offset, selection_bound;
1309 gboolean selection_changed;
1311 insert_offset = gtk_text_iter_get_offset (location);
1313 selection_bound = get_selection_bound (buffer);
1314 if (selection_bound != insert_offset)
1316 if (selection_bound != accessible->previous_selection_bound ||
1317 insert_offset != accessible->previous_insert_offset)
1318 selection_changed = TRUE;
1320 selection_changed = FALSE;
1322 else if (accessible->previous_selection_bound != accessible->previous_insert_offset)
1323 selection_changed = TRUE;
1325 selection_changed = FALSE;
1327 emit_text_caret_moved (accessible, insert_offset);
1329 * insert and selection_bound marks are different to a selection
1332 if (selection_changed)
1333 g_signal_emit_by_name (accessible, "text_selection_changed");
1334 accessible->previous_selection_bound = selection_bound;
1339 changed_cb (GtkTextBuffer *buffer,
1342 GtkTextView *text = data;
1343 GtkTextViewAccessible *accessible;
1345 accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
1346 if (accessible->signal_name)
1348 if (!accessible->insert_notify_handler)
1350 accessible->insert_notify_handler = gdk_threads_add_idle (insert_idle_handler, accessible);
1354 emit_text_caret_moved (accessible, get_insert_offset (buffer));
1355 accessible->previous_selection_bound = get_selection_bound (buffer);
1359 insert_idle_handler (gpointer data)
1361 GtkTextViewAccessible *accessible = data;
1363 GtkTextBuffer *buffer;
1365 g_signal_emit_by_name (data,
1366 accessible->signal_name,
1367 accessible->position,
1368 accessible->length);
1369 accessible->signal_name = NULL;
1370 accessible->position = 0;
1371 accessible->length = 0;
1373 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
1374 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1375 if (accessible->insert_notify_handler)
1378 * If called from idle handler notify caret moved
1380 accessible->insert_notify_handler = 0;
1381 emit_text_caret_moved (accessible, get_insert_offset (buffer));
1382 accessible->previous_selection_bound = get_selection_bound (buffer);
1389 gail_streamable_content_get_n_mime_types (AtkStreamableContent *streamable)
1392 GtkTextBuffer *buffer;
1393 gint n_mime_types = 0;
1395 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1399 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1403 gboolean advertises_plaintext = FALSE;
1406 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1407 for (i = 0; i < n_mime_types-1; ++i)
1408 if (!strcmp ("text/plain", gdk_atom_name (atoms[i])))
1409 advertises_plaintext = TRUE;
1410 if (!advertises_plaintext)
1414 return n_mime_types;
1417 static const gchar *
1418 gail_streamable_content_get_mime_type (AtkStreamableContent *streamable,
1422 GtkTextBuffer *buffer;
1424 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1428 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1431 gint n_mime_types = 0;
1434 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1435 if (i < n_mime_types)
1436 return gdk_atom_name (atoms [i]);
1437 else if (i == n_mime_types)
1438 return "text/plain";
1445 gail_streamable_content_get_stream (AtkStreamableContent *streamable,
1446 const gchar *mime_type)
1449 GtkTextBuffer *buffer;
1450 gint i, n_mime_types = 0;
1453 widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (streamable));
1457 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
1461 atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_mime_types);
1463 for (i = 0; i < n_mime_types; ++i)
1465 if (!strcmp ("text/plain", mime_type) ||
1466 !strcmp (gdk_atom_name (atoms[i]), mime_type))
1472 GtkTextIter start, end;
1473 GIOChannel *gio = NULL;
1476 gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
1477 gtk_text_buffer_get_iter_at_offset (buffer, &end, -1);
1478 if (!strcmp ("text/plain", mime_type))
1480 cbuf = (guint8*) gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1481 len = strlen ((const char *) cbuf);
1485 cbuf = gtk_text_buffer_serialize (buffer, buffer, atoms[i], &start, &end, &len);
1487 g_snprintf (tname, 20, "streamXXXXXX");
1488 fd = g_mkstemp (tname);
1489 gio = g_io_channel_unix_new (fd);
1490 g_io_channel_set_encoding (gio, NULL, &err);
1492 g_io_channel_write_chars (gio, (const char *) cbuf, (gssize) len, &written, &err);
1494 g_message ("%s", err->message);
1496 g_io_channel_seek_position (gio, 0, G_SEEK_SET, &err);
1498 g_message ("%s", err->message);
1500 g_io_channel_flush (gio, &err);
1502 g_message ("%s", err->message);
1505 g_message ("<error writing to stream [%s]>", tname);
1508 /* make sure the file is removed on unref of the giochannel */
1521 atk_streamable_content_interface_init (AtkStreamableContentIface *iface)
1523 iface->get_n_mime_types = gail_streamable_content_get_n_mime_types;
1524 iface->get_mime_type = gail_streamable_content_get_mime_type;
1525 iface->get_stream = gail_streamable_content_get_stream;