diff options
Diffstat (limited to 'e-util/gal-a11y-e-text.c')
-rw-r--r-- | e-util/gal-a11y-e-text.c | 1141 |
1 files changed, 1141 insertions, 0 deletions
diff --git a/e-util/gal-a11y-e-text.c b/e-util/gal-a11y-e-text.c new file mode 100644 index 0000000000..9b03a78483 --- /dev/null +++ b/e-util/gal-a11y-e-text.c @@ -0,0 +1,1141 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Christopher James Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "gal-a11y-e-text.h" + +#include <string.h> + +#include <gtk/gtk.h> + +#include "e-text.h" +#include "e-text-model-repos.h" +#include "gal-a11y-e-text-factory.h" +#include "gal-a11y-util.h" + +static GObjectClass *parent_class; +static AtkComponentIface *component_parent_iface; +static GType parent_type; +static gint priv_offset; +static GQuark quark_accessible_object = 0; +#define PARENT_TYPE (parent_type) + +struct _GalA11yETextPrivate { + gint dummy; +}; + +static void +et_dispose (GObject *object) +{ + if (parent_class->dispose) + parent_class->dispose (object); +} + +/* Static functions */ + +static void +et_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + EText *item = E_TEXT (atk_gobject_accessible_get_object ( + ATK_GOBJECT_ACCESSIBLE (component))); + gdouble real_width; + gdouble real_height; + gint fake_width; + gint fake_height; + + if (component_parent_iface && + component_parent_iface->get_extents) + component_parent_iface->get_extents (component, + x, + y, + &fake_width, + &fake_height, + coord_type); + + g_object_get ( + item, + "text_width", &real_width, + "text_height", &real_height, + NULL); + + if (width) + *width = real_width; + if (height) + *height = real_height; +} + +static const gchar * +et_get_full_text (AtkText *text) +{ + GObject *obj; + EText *etext; + ETextModel *model; + const gchar *full_text; + + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return ""; + + etext = E_TEXT (obj); + g_object_get (etext, "model", &model, NULL); + + full_text = e_text_model_get_text (model); + + return full_text; +} + +static void +et_set_full_text (AtkEditableText *text, + const gchar *full_text) +{ + GObject *obj; + EText *etext; + ETextModel *model; + + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + etext = E_TEXT (obj); + g_object_get (etext, "model", &model, NULL); + + e_text_model_set_text (model, full_text); +} + +static gchar * +et_get_text (AtkText *text, + gint start_offset, + gint end_offset) +{ + gint start, end, real_start, real_end, len; + const gchar *full_text = et_get_full_text (text); + if (full_text == NULL) + return NULL; + len = g_utf8_strlen (full_text, -1); + + start = MIN (MAX (0, start_offset), len); + end = MIN (MAX (-1, end_offset), len); + + if (end_offset == -1) + end = strlen (full_text); + else + end = g_utf8_offset_to_pointer (full_text, end) - full_text; + + start = g_utf8_offset_to_pointer (full_text, start) - full_text; + + real_start = MIN (start, end); + real_end = MAX (start, end); + + return g_strndup (full_text + real_start, real_end - real_start); +} + +static gboolean +is_a_seperator (gunichar c) +{ + return g_unichar_ispunct (c) || g_unichar_isspace (c); +} + +static gint +find_word_start (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar current, previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if ((!is_a_seperator (current)) && is_a_seperator (previous)) + break; + offset += step; + } + + return offset; +} + +static gint +find_word_end (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar current, previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (is_a_seperator (current) && (!is_a_seperator (previous))) + break; + offset += step; + } + + return offset; +} + +static gint +find_sentence_start (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset, last_word_end, len; + gchar *at_offset; + gunichar ch; + gint i; + + offset = find_word_start (text, begin_offset, step); + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset <len) { + last_word_end = find_word_end (text, offset - 1, -1); + if (last_word_end == 0) + break; + for (i = last_word_end; i < offset; i++) { + at_offset = g_utf8_offset_to_pointer (text, i); + ch = g_utf8_get_char_validated (at_offset, -1); + if (ch == '.' || ch == '!' || ch == '?') + return offset; + } + + offset = find_word_start (text, offset + step, step); + } + + return offset; +} + +static gint +find_sentence_end (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (previous == '.' || previous == '!' || previous == '?') + break; + offset += step; + } + + return offset; +} + +static gint +find_line_start (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar previous; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset > 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset - 1); + previous = g_utf8_get_char_validated (at_offset, -1); + if (previous == '\n' || previous == '\r') + break; + offset += step; + } + + return offset; +} + +static gint +find_line_end (const gchar *text, + gint begin_offset, + gint step) +{ + gint offset; + gchar *at_offset; + gunichar current; + gint len; + + offset = begin_offset; + len = g_utf8_strlen (text, -1); + + while (offset >= 0 && offset < len) { + at_offset = g_utf8_offset_to_pointer (text, offset); + current = g_utf8_get_char_validated (at_offset, -1); + if (current == '\n' || current == '\r') + break; + offset += step; + } + + return offset; +} + +static gchar * +et_get_text_after_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const gchar *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset + 1; + end = offset + 2; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + start = find_word_start (full_text, offset + 1, 1); + end = find_word_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + start = find_word_end (full_text, offset + 1, 1); + end = find_word_end (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + start = find_sentence_start (full_text, offset + 1, 1); + end = find_sentence_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + start = find_sentence_end (full_text, offset + 1, 1); + end = find_sentence_end (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + start = find_line_start (full_text, offset + 1, 1); + end = find_line_start (full_text, start + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + start = find_line_end (full_text, offset + 1, 1); + end = find_line_end (full_text, start + 1, 1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gchar * +et_get_text_at_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const gchar *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset; + end = offset + 1; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + start = find_word_start (full_text, offset - 1, -1); + end = find_word_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + start = find_word_end (full_text, offset, -1); + end = find_word_end (full_text, offset + 1, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + start = find_sentence_start (full_text, offset - 1, -1); + end = find_sentence_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + start = find_sentence_end (full_text, offset, -1); + end = find_sentence_end (full_text, offset + 1, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + start = find_line_start (full_text, offset - 1, -1); + end = find_line_start (full_text, offset, 1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + start = find_line_end (full_text, offset, -1); + end = find_line_end (full_text, offset + 1, 1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gunichar +et_get_character_at_offset (AtkText *text, + gint offset) +{ + const gchar *full_text = et_get_full_text (text); + gchar *at_offset; + + at_offset = g_utf8_offset_to_pointer (full_text, offset); + return g_utf8_get_char_validated (at_offset, -1); +} + +static gchar * +et_get_text_before_offset (AtkText *text, + gint offset, + AtkTextBoundary boundary_type, + gint *start_offset, + gint *end_offset) +{ + gint start, end, len; + const gchar *full_text = et_get_full_text (text); + g_return_val_if_fail (full_text, NULL); + + switch (boundary_type) + { + case ATK_TEXT_BOUNDARY_CHAR: + start = offset - 1; + end = offset; + break; + case ATK_TEXT_BOUNDARY_WORD_START: + end = find_word_start (full_text, offset - 1, -1); + start = find_word_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_WORD_END: + end = find_word_end (full_text, offset, -1); + start = find_word_end (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_START: + end = find_sentence_start (full_text, offset, -1); + start = find_sentence_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_SENTENCE_END: + end = find_sentence_end (full_text, offset, -1); + start = find_sentence_end (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_LINE_START: + end = find_line_start (full_text, offset, -1); + start = find_line_start (full_text, end - 1, -1); + break; + case ATK_TEXT_BOUNDARY_LINE_END: + end = find_line_end (full_text, offset, -1); + start = find_line_end (full_text, end - 1, -1); + break; + default: + return NULL; + } + + len = g_utf8_strlen (full_text, -1); + if (start_offset) + *start_offset = MIN (MAX (0, start), len); + if (end_offset) + *end_offset = MIN (MAX (0, end), len); + return et_get_text (text, start, end); +} + +static gint +et_get_caret_offset (AtkText *text) +{ + GObject *obj; + EText *etext; + gint offset; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), -1); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return -1; + + g_return_val_if_fail (E_IS_TEXT (obj), -1); + etext = E_TEXT (obj); + + g_object_get (etext, "cursor_pos", &offset, NULL); + return offset; +} + +static AtkAttributeSet * +et_get_run_attributes (AtkText *text, + gint offset, + gint *start_offset, + gint *end_offset) +{ + /* Unimplemented */ + return NULL; +} + +static AtkAttributeSet * +et_get_default_attributes (AtkText *text) +{ + /* Unimplemented */ + return NULL; +} + +static void +et_get_character_extents (AtkText *text, + gint offset, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coords) +{ + GObject *obj; + EText *etext; + GnomeCanvas *canvas; + gint x_widget, y_widget, x_window, y_window; + GdkWindow *window; + GtkWidget *widget; + PangoRectangle pango_pos; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + canvas = GNOME_CANVAS_ITEM (etext)->canvas; + widget = GTK_WIDGET (canvas); + window = gtk_widget_get_window (widget); + gdk_window_get_origin (window, &x_widget, &y_widget); + + pango_layout_index_to_pos (etext->layout, offset, &pango_pos); + pango_pos.x = PANGO_PIXELS (pango_pos.x); + pango_pos.y = PANGO_PIXELS (pango_pos.y); + pango_pos.width = (pango_pos.width + PANGO_SCALE / 2) / PANGO_SCALE; + pango_pos.height = (pango_pos.height + PANGO_SCALE / 2) / PANGO_SCALE; + + *x = pango_pos.x + x_widget; + *y = pango_pos.y + y_widget; + + *width = pango_pos.width; + *height = pango_pos.height; + + *x += etext->xofs; + *y += etext->yofs; + + if (etext->editing) { + *x -= etext->xofs_edit; + *y -= etext->yofs_edit; + } + + *x += etext->cx; + *y += etext->cy; + + if (coords == ATK_XY_WINDOW) { + window = gdk_window_get_toplevel (window); + gdk_window_get_origin (window, &x_window, &y_window); + *x -= x_window; + *y -= y_window; + } + else if (coords == ATK_XY_SCREEN) { + } + else { + *x = 0; + *y = 0; + *height = 0; + *width = 0; + } +} + +static gint +et_get_character_count (AtkText *text) +{ + const gchar *full_text = et_get_full_text (text); + + return g_utf8_strlen (full_text, -1); +} + +static gint +et_get_offset_at_point (AtkText *text, + gint x, + gint y, + AtkCoordType coords) +{ + GObject *obj; + EText *etext; + GnomeCanvas *canvas; + gint x_widget, y_widget, x_window, y_window; + GdkWindow *window; + GtkWidget *widget; + gint index; + gint trailing; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), -1); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return -1; + g_return_val_if_fail (E_IS_TEXT (obj), -1); + etext = E_TEXT (obj); + canvas = GNOME_CANVAS_ITEM (etext)->canvas; + widget = GTK_WIDGET (canvas); + window = gtk_widget_get_window (widget); + gdk_window_get_origin (window, &x_widget, &y_widget); + + if (coords == ATK_XY_SCREEN) { + x = x - x_widget; + y = y - y_widget; + } + else if (coords == ATK_XY_WINDOW) { + window = gdk_window_get_toplevel (window); + gdk_window_get_origin (window, &x_window, &y_window); + x = x - x_widget + x_window; + y = y - y_widget + y_window; + } + else + return -1; + + x -= etext->xofs; + y -= etext->yofs; + + if (etext->editing) { + x += etext->xofs_edit; + y += etext->yofs_edit; + } + + x -= etext->cx; + y -= etext->cy; + + pango_layout_xy_to_index ( + etext->layout, + x * PANGO_SCALE - PANGO_SCALE / 2, + y * PANGO_SCALE - PANGO_SCALE / 2, + &index, + &trailing); + + return g_utf8_pointer_to_offset (etext->text, etext->text + index + trailing); +} + +static gint +et_get_n_selections (AtkText *text) +{ + EText *etext; + GObject *obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + + if (obj == NULL) + return -1; + etext = E_TEXT (obj); + + if (etext->selection_start != + etext->selection_end) + return 1; + return 0; +} + +static gchar * +et_get_selection (AtkText *text, + gint selection_num, + gint *start_offset, + gint *end_offset) +{ + gint start, end, real_start, real_end, len; + EText *etext; + if (selection_num == 0) { + const gchar *full_text = et_get_full_text (text); + if (full_text == NULL) + return NULL; + len = g_utf8_strlen (full_text, -1); + etext = E_TEXT (atk_gobject_accessible_get_object ( + ATK_GOBJECT_ACCESSIBLE (text))); + start = MIN (etext->selection_start, etext->selection_end); + end = MAX (etext->selection_start, etext->selection_end); + start = MIN (MAX (0, start), len); + end = MIN (MAX (0, end), len); + if (start != end) { + if (start_offset) + *start_offset = start; + if (end_offset) + *end_offset = end; + real_start = g_utf8_offset_to_pointer (full_text, start) - full_text; + real_end = g_utf8_offset_to_pointer (full_text, end) - full_text; + return g_strndup (full_text + real_start, real_end - real_start); + } + } + + return NULL; +} + +static gboolean +et_add_selection (AtkText *text, + gint start_offset, + gint end_offset) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + g_return_val_if_fail (start_offset >= 0, FALSE); + g_return_val_if_fail (start_offset >= -1, FALSE); + if (end_offset == -1) + end_offset = et_get_character_count (text); + + if (start_offset != end_offset) { + gint real_start, real_end; + real_start = MIN (start_offset, end_offset); + real_end = MAX (start_offset, end_offset); + etext->selection_start = real_start; + etext->selection_end = real_end; + + gnome_canvas_item_grab_focus (GNOME_CANVAS_ITEM (etext)); + gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (etext)); + + g_signal_emit_by_name (ATK_OBJECT (text), "text_selection_changed"); + + return TRUE; + } + + return FALSE; +} + +static gboolean +et_remove_selection (AtkText *text, + gint selection_num) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + if (selection_num == 0 + && etext->selection_start != etext->selection_end) { + etext->selection_end = etext->selection_start; + g_signal_emit_by_name (ATK_OBJECT (text), "text_selection_changed"); + return TRUE; + } + + return FALSE; +} + +static gboolean +et_set_selection (AtkText *text, + gint selection_num, + gint start_offset, + gint end_offset) +{ + GObject *obj; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + if (selection_num == 0) + return et_add_selection (text, start_offset, end_offset); + return FALSE; +} + +static gboolean +et_set_caret_offset (AtkText *text, + gint offset) +{ + GObject *obj; + EText *etext; + + g_return_val_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text), FALSE); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return FALSE; + + g_return_val_if_fail (E_IS_TEXT (obj), FALSE); + etext = E_TEXT (obj); + + if (offset < -1) + return FALSE; + else { + ETextEventProcessorCommand command; + + if (offset == -1) + offset = et_get_character_count (text); + + command.action = E_TEP_MOVE; + command.position = E_TEP_VALUE; + command.value = offset; + command.time = GDK_CURRENT_TIME; + g_signal_emit_by_name (etext->tep, "command", &command); + return TRUE; + } +} + +static gboolean +et_set_run_attributes (AtkEditableText *text, + AtkAttributeSet *attrib_set, + gint start_offset, + gint end_offset) +{ + /* Unimplemented */ + return FALSE; +} + +static void +et_set_text_contents (AtkEditableText *text, + const gchar *string) +{ + et_set_full_text (text, string); +} + +static void +et_insert_text (AtkEditableText *text, + const gchar *string, + gint length, + gint *position) +{ + /* Utf8 unimplemented */ + gchar *result; + + const gchar *full_text = et_get_full_text (ATK_TEXT (text)); + if (full_text == NULL) + return; + + result = g_strdup_printf ( + "%.*s%.*s%s", *position, full_text, + length, string, full_text + *position); + + et_set_full_text (text, result); + + *position += length; + + g_free (result); +} + +static void +et_copy_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + if (start_pos != end_pos) { + etext->selection_start = start_pos; + etext->selection_end = end_pos; + e_text_copy_clipboard (etext); + } +} + +static void +et_delete_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + etext->selection_start = start_pos; + etext->selection_end = end_pos; + + e_text_delete_selection (etext); +} + +static void +et_cut_text (AtkEditableText *text, + gint start_pos, + gint end_pos) +{ + et_copy_text (text, start_pos, end_pos); + et_delete_text (text, start_pos, end_pos); +} + +static void +et_paste_text (AtkEditableText *text, + gint position) +{ + GObject *obj; + EText *etext; + + g_return_if_fail (ATK_IS_GOBJECT_ACCESSIBLE (text)); + obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (text)); + if (obj == NULL) + return; + + g_return_if_fail (E_IS_TEXT (obj)); + etext = E_TEXT (obj); + + g_object_set (etext, "cursor_pos", position, NULL); + e_text_paste_clipboard (etext); +} + +static void +et_atk_component_iface_init (AtkComponentIface *iface) +{ + iface->get_extents = et_get_extents; +} + +static void +et_atk_text_iface_init (AtkTextIface *iface) +{ + iface->get_text = et_get_text; + iface->get_text_after_offset = et_get_text_after_offset; + iface->get_text_at_offset = et_get_text_at_offset; + iface->get_character_at_offset = et_get_character_at_offset; + iface->get_text_before_offset = et_get_text_before_offset; + iface->get_caret_offset = et_get_caret_offset; + iface->get_run_attributes = et_get_run_attributes; + iface->get_default_attributes = et_get_default_attributes; + iface->get_character_extents = et_get_character_extents; + iface->get_character_count = et_get_character_count; + iface->get_offset_at_point = et_get_offset_at_point; + iface->get_n_selections = et_get_n_selections; + iface->get_selection = et_get_selection; + iface->add_selection = et_add_selection; + iface->remove_selection = et_remove_selection; + iface->set_selection = et_set_selection; + iface->set_caret_offset = et_set_caret_offset; +} + +static void +et_atk_editable_text_iface_init (AtkEditableTextIface *iface) +{ + iface->set_run_attributes = et_set_run_attributes; + iface->set_text_contents = et_set_text_contents; + iface->insert_text = et_insert_text; + iface->copy_text = et_copy_text; + iface->cut_text = et_cut_text; + iface->delete_text = et_delete_text; + iface->paste_text = et_paste_text; +} + +static void +_et_reposition_cb (ETextModel *model, + ETextModelReposFn fn, + gpointer repos_data, + gpointer user_data) +{ + AtkObject *accessible; + AtkText *text; + + accessible = ATK_OBJECT (user_data); + text = ATK_TEXT (accessible); + + if (fn == e_repos_delete_shift) { + EReposDeleteShift *info = (EReposDeleteShift *) repos_data; + g_signal_emit_by_name (text, "text-changed::delete", info->pos, info->len); + } + else if (fn == e_repos_insert_shift) { + EReposInsertShift *info = (EReposInsertShift *) repos_data; + g_signal_emit_by_name (text, "text-changed::insert", info->pos, info->len); + } +} + +static void +_et_command_cb (ETextEventProcessor *tep, + ETextEventProcessorCommand *command, + gpointer user_data) +{ + AtkObject *accessible; + AtkText *text; + + accessible = ATK_OBJECT (user_data); + text = ATK_TEXT (accessible); + + switch (command->action) { + case E_TEP_MOVE: + g_signal_emit_by_name (text, "text-caret-moved", et_get_caret_offset (text)); + break; + case E_TEP_SELECT: + g_signal_emit_by_name (text, "text-selection-changed"); + break; + default: + break; + } +} + +static void +et_real_initialize (AtkObject *obj, + gpointer data) +{ + EText *etext; + + ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); + + g_return_if_fail (GAL_A11Y_IS_E_TEXT (obj)); + g_return_if_fail (E_IS_TEXT (data)); + + etext = E_TEXT (data); + + /* Set up signal callbacks */ + g_signal_connect ( + etext->model, "reposition", + G_CALLBACK (_et_reposition_cb), obj); + + if (etext->tep) + g_signal_connect_after ( + etext->tep, "command", + (GCallback) _et_command_cb, obj); + + obj->role = ATK_ROLE_TEXT; +} + +static void +et_class_init (GalA11yETextClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (class); + + quark_accessible_object = + g_quark_from_static_string ("gtk-accessible-object"); + parent_class = g_type_class_ref (PARENT_TYPE); + component_parent_iface = + g_type_interface_peek (parent_class, ATK_TYPE_COMPONENT); + object_class->dispose = et_dispose; + atk_class->initialize = et_real_initialize; +} + +static void +et_init (GalA11yEText *a11y) +{ +} + +/** + * gal_a11y_e_text_get_type: + * @void: + * + * Registers the &GalA11yEText class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &GalA11yEText class. + **/ +GType +gal_a11y_e_text_get_type (void) +{ + static GType type = 0; + + if (!type) { + AtkObjectFactory *factory; + + GTypeInfo info = { + sizeof (GalA11yETextClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) et_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (GalA11yEText), + 0, + (GInstanceInitFunc) et_init, + NULL /* value_text */ + }; + + static const GInterfaceInfo atk_component_info = { + (GInterfaceInitFunc) et_atk_component_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_text_info = { + (GInterfaceInitFunc) et_atk_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + static const GInterfaceInfo atk_editable_text_info = { + (GInterfaceInitFunc) et_atk_editable_text_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL + }; + + factory = atk_registry_get_factory ( + atk_get_default_registry (), GNOME_TYPE_CANVAS_ITEM); + parent_type = atk_object_factory_get_accessible_type (factory); + + type = gal_a11y_type_register_static_with_private ( + PARENT_TYPE, "GalA11yEText", &info, 0, + sizeof (GalA11yETextPrivate), &priv_offset); + + g_type_add_interface_static ( + type, ATK_TYPE_COMPONENT, &atk_component_info); + g_type_add_interface_static ( + type, ATK_TYPE_TEXT, &atk_text_info); + g_type_add_interface_static ( + type, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info); + } + + return type; +} + +void +gal_a11y_e_text_init (void) +{ + if (atk_get_root ()) + atk_registry_set_factory_type ( + atk_get_default_registry (), + E_TYPE_TEXT, + gal_a11y_e_text_factory_get_type ()); + +} + |