Implement GtkAccessibleText for GtkText

This commit is contained in:
Matthias Clasen 2024-02-01 13:42:01 +01:00
parent eeee3151b6
commit a44701faa2

View File

@ -23,6 +23,7 @@
#include "gtktextprivate.h"
#include "gtkaccessibletext-private.h"
#include "gtkactionable.h"
#include "gtkadjustment.h"
#include "gtkbox.h"
@ -69,6 +70,8 @@
#include "gtkactionmuxerprivate.h"
#include "gtkjoinedmenuprivate.h"
#include "deprecated/gtkrender.h"
#include "gtkaccessibletext-private.h"
#include "a11y/gtkatspipangoprivate.h"
#include <cairo-gobject.h>
#include <string.h>
@ -706,9 +709,14 @@ static const GtkTextHistoryFuncs history_funcs = {
gtk_text_history_select_cb,
};
static void gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkText, gtk_text, GTK_TYPE_WIDGET,
G_ADD_PRIVATE (GtkText)
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_text_editable_init))
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_text_editable_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE_TEXT,
gtk_text_accessible_text_init))
static void
add_move_binding (GtkWidgetClass *widget_class,
@ -3440,6 +3448,11 @@ gtk_text_insert_text (GtkText *self,
if (n_inserted != n_chars)
gtk_widget_error_bell (GTK_WIDGET (self));
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
*position,
n_inserted);
*position += n_inserted;
update_placeholder_visibility (self);
@ -3460,6 +3473,11 @@ gtk_text_delete_text (GtkText *self,
if (start_pos == end_pos)
return;
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_REMOVE,
start_pos,
end_pos);
if (priv->change_count == 0)
gtk_text_history_begin_irreversible_action (priv->history);
begin_change (self);
@ -3484,6 +3502,9 @@ gtk_text_delete_selection (GtkText *self)
int end_pos = MAX (priv->selection_bound, priv->current_pos);
gtk_editable_delete_text (GTK_EDITABLE (self), start_pos, end_pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_REMOVE,
start_pos, end_pos);
}
static void
@ -3504,6 +3525,9 @@ gtk_text_set_selection_bounds (GtkText *self,
gtk_text_set_positions (self, MIN (end, length), MIN (start, length));
gtk_text_update_primary_selection (self);
gtk_accessible_text_update_caret_position (GTK_ACCESSIBLE_TEXT (self));
gtk_accessible_text_update_selection_bound (GTK_ACCESSIBLE_TEXT (self));
}
static gboolean
@ -3985,6 +4009,10 @@ gtk_text_insert_at_cursor (GtkText *self,
begin_change (self);
gtk_text_reset_im_context (self);
gtk_editable_insert_text (GTK_EDITABLE (self), str, -1, &pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
pos,
pos + g_utf8_strlen (str, -1));
gtk_text_set_selection_bounds (self, pos, pos);
end_change (self);
}
@ -4059,7 +4087,6 @@ gtk_text_delete_from_cursor (GtkText *self,
gtk_editable_delete_text (GTK_EDITABLE (self), 0, priv->current_pos);
else
gtk_editable_delete_text (GTK_EDITABLE (self), priv->current_pos, -1);
break;
case GTK_DELETE_DISPLAY_LINES:
@ -4139,8 +4166,12 @@ gtk_text_backspace (GtkText *self)
int pos = priv->current_pos;
gtk_editable_insert_text (GTK_EDITABLE (self), normalized_text,
g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
&pos);
g_utf8_offset_to_pointer (normalized_text, len - 1) - normalized_text,
&pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
pos,
pos + len);
gtk_text_set_selection_bounds (self, pos, pos);
}
@ -4426,6 +4457,9 @@ gtk_text_enter_text (GtkText *self,
tmp_pos = priv->current_pos;
gtk_editable_insert_text (GTK_EDITABLE (self), str, strlen (str), &tmp_pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
tmp_pos, tmp_pos + g_utf8_strlen (str, -1));
gtk_text_set_selection_bounds (self, tmp_pos, tmp_pos);
end_change (self);
@ -5389,6 +5423,9 @@ paste_received (GObject *clipboard,
pos = priv->current_pos;
gtk_editable_insert_text (GTK_EDITABLE (self), text, length, &pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
pos, pos + length);
gtk_text_set_selection_bounds (self, pos, pos);
end_change (self);
@ -5620,8 +5657,14 @@ gtk_text_set_text (GtkText *self,
begin_change (self);
g_object_freeze_notify (G_OBJECT (self));
gtk_editable_delete_text (GTK_EDITABLE (self), 0, -1);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_REMOVE,
0, G_MAXUINT);
tmp_pos = 0;
gtk_editable_insert_text (GTK_EDITABLE (self), text, strlen (text), &tmp_pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
tmp_pos, tmp_pos + g_utf8_strlen (text, -1));
g_object_thaw_notify (G_OBJECT (self));
end_change (self);
@ -6420,6 +6463,9 @@ gtk_text_drag_drop (GtkDropTarget *dest,
drop_position > priv->current_pos)
{
gtk_editable_insert_text (GTK_EDITABLE (self), str, length, &drop_position);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
drop_position, drop_position + length);
}
else
{
@ -6429,6 +6475,9 @@ gtk_text_drag_drop (GtkDropTarget *dest,
gtk_text_delete_selection (self);
pos = MIN (priv->selection_bound, priv->current_pos);
gtk_editable_insert_text (GTK_EDITABLE (self), str, length, &pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
pos, pos + length);
end_change (self);
}
@ -7004,6 +7053,9 @@ emoji_picked (GtkEmojiChooser *chooser,
pos = priv->current_pos;
gtk_editable_insert_text (GTK_EDITABLE (self), text, -1, &pos);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (self),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
pos, pos + 1);
gtk_text_set_selection_bounds (self, pos, pos);
end_change (self);
}
@ -7331,6 +7383,9 @@ gtk_text_history_insert_cb (gpointer funcs_data,
int location = begin;
gtk_editable_insert_text (GTK_EDITABLE (text), str, len, &location);
gtk_accessible_text_update_contents (GTK_ACCESSIBLE_TEXT (text),
GTK_ACCESSIBLE_TEXT_CONTENT_CHANGE_INSERT,
location, location + len);
}
static void
@ -7381,3 +7436,104 @@ gtk_text_update_history (GtkText *self)
priv->visible &&
priv->editable);
}
/* {{{ GtkAccessibleText implementation */
static GBytes *
gtk_text_accessible_text_get_contents (GtkAccessibleText *self,
unsigned int start,
unsigned int end)
{
const char *text;
int len;
char *string;
gsize size;
text = gtk_editable_get_text (GTK_EDITABLE (self));
len = g_utf8_strlen (text, -1);
start = CLAMP (start, 0, len);
end = CLAMP (end, 0, len);
if (end <= start)
{
string = g_strdup ("");
size = 1;
}
else
{
const char *p, *q;
p = g_utf8_offset_to_pointer (text, start);
q = g_utf8_offset_to_pointer (text, end);
size = q - p + 1;
string = g_strndup (p, q - p);
}
return g_bytes_new_take (string, size);
}
static unsigned int
gtk_text_accessible_text_get_caret_position (GtkAccessibleText *self)
{
return gtk_editable_get_position (GTK_EDITABLE (self));
}
static gboolean
gtk_text_accessible_text_get_selection (GtkAccessibleText *self,
gsize *n_ranges,
GtkAccessibleTextRange **ranges)
{
int start, end;
if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (self), &start, &end))
return FALSE;
*n_ranges = 1;
*ranges = g_new (GtkAccessibleTextRange, 1);
(*ranges)[0].start = start;
(*ranges)[0].length = end - start;
return TRUE;
}
static gboolean
gtk_text_accessible_text_get_attributes (GtkAccessibleText *self,
unsigned int offset,
gsize *n_ranges,
GtkAccessibleTextRange **ranges,
char ***attribute_names,
char ***attribute_values)
{
PangoLayout *layout = gtk_text_get_layout (GTK_TEXT (self));
unsigned int start, end;
char **names, **values;
gtk_pango_get_run_attributes (layout, offset, &names, &values, &start, &end);
*n_ranges = g_strv_length (names);
*ranges = g_new (GtkAccessibleTextRange, *n_ranges);
for (unsigned i = 0; i < *n_ranges; i++)
{
GtkAccessibleTextRange *range = &(*ranges)[i];
range->start = start;
range->length = end - start;
}
*attribute_names = names;
*attribute_values = values;
return TRUE;
}
static void
gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface)
{
iface->get_contents = gtk_text_accessible_text_get_contents;
iface->get_caret_position = gtk_text_accessible_text_get_caret_position;
iface->get_selection = gtk_text_accessible_text_get_selection;
iface->get_attributes = gtk_text_accessible_text_get_attributes;
}
/* vim:set foldmethod=marker expandtab: */