a11y: Redo TextView cursor/selection signal handling
As part of the removal of idles, redo how we emit signals on the accessible. Should work as good or better than before, but with a lot less code.
This commit is contained in:
@ -40,13 +40,10 @@ static void delete_range_cb (GtkTextBuffer *buffer,
|
|||||||
GtkTextIter *arg1,
|
GtkTextIter *arg1,
|
||||||
GtkTextIter *arg2,
|
GtkTextIter *arg2,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
static void changed_cb (GtkTextBuffer *buffer,
|
|
||||||
gpointer user_data);
|
|
||||||
static void mark_set_cb (GtkTextBuffer *buffer,
|
static void mark_set_cb (GtkTextBuffer *buffer,
|
||||||
GtkTextIter *arg1,
|
GtkTextIter *arg1,
|
||||||
GtkTextMark *arg2,
|
GtkTextMark *arg2,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
static gint insert_idle_handler (gpointer data);
|
|
||||||
|
|
||||||
|
|
||||||
static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
|
static void atk_editable_text_interface_init (AtkEditableTextIface *iface);
|
||||||
@ -70,17 +67,6 @@ gtk_text_view_accessible_initialize (AtkObject *obj,
|
|||||||
obj->role = ATK_ROLE_TEXT;
|
obj->role = ATK_ROLE_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_text_view_accessible_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
GtkTextViewAccessible *text_view = GTK_TEXT_VIEW_ACCESSIBLE (object);
|
|
||||||
|
|
||||||
if (text_view->insert_notify_handler)
|
|
||||||
g_source_remove (text_view->insert_notify_handler);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_text_view_accessible_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_text_view_accessible_notify_gtk (GObject *obj,
|
gtk_text_view_accessible_notify_gtk (GObject *obj,
|
||||||
GParamSpec *pspec)
|
GParamSpec *pspec)
|
||||||
@ -126,12 +112,9 @@ gtk_text_view_accessible_ref_state_set (AtkObject *accessible)
|
|||||||
static void
|
static void
|
||||||
gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
|
gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
||||||
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
|
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
|
||||||
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
|
GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass;
|
||||||
|
|
||||||
gobject_class->finalize = gtk_text_view_accessible_finalize;
|
|
||||||
|
|
||||||
class->ref_state_set = gtk_text_view_accessible_ref_state_set;
|
class->ref_state_set = gtk_text_view_accessible_ref_state_set;
|
||||||
class->initialize = gtk_text_view_accessible_initialize;
|
class->initialize = gtk_text_view_accessible_initialize;
|
||||||
|
|
||||||
@ -141,10 +124,6 @@ gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass)
|
|||||||
static void
|
static void
|
||||||
gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
|
gtk_text_view_accessible_init (GtkTextViewAccessible *accessible)
|
||||||
{
|
{
|
||||||
accessible->signal_name = NULL;
|
|
||||||
accessible->previous_insert_offset = -1;
|
|
||||||
accessible->previous_selection_bound = -1;
|
|
||||||
accessible->insert_notify_handler = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -156,10 +135,9 @@ setup_buffer (GtkTextView *view,
|
|||||||
buffer = gtk_text_view_get_buffer (view);
|
buffer = gtk_text_view_get_buffer (view);
|
||||||
|
|
||||||
/* Set up signal callbacks */
|
/* Set up signal callbacks */
|
||||||
g_signal_connect (buffer, "insert-text", G_CALLBACK (insert_text_cb), view);
|
g_signal_connect_after (buffer, "insert-text", G_CALLBACK (insert_text_cb), view);
|
||||||
g_signal_connect (buffer, "delete-range", G_CALLBACK (delete_range_cb), view);
|
g_signal_connect (buffer, "delete-range", G_CALLBACK (delete_range_cb), view);
|
||||||
g_signal_connect (buffer, "mark-set", G_CALLBACK (mark_set_cb), view);
|
g_signal_connect_after (buffer, "mark-set", G_CALLBACK (mark_set_cb), view);
|
||||||
g_signal_connect (buffer, "changed", G_CALLBACK (changed_cb), view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
@ -1162,6 +1140,35 @@ atk_editable_text_interface_init (AtkEditableTextIface *iface)
|
|||||||
|
|
||||||
/* Callbacks */
|
/* Callbacks */
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_text_view_accessible_update_cursor (GtkTextViewAccessible *accessible,
|
||||||
|
GtkTextBuffer * buffer)
|
||||||
|
{
|
||||||
|
int prev_insert_offset, prev_selection_bound;
|
||||||
|
int insert_offset, selection_bound;
|
||||||
|
GtkTextIter iter;
|
||||||
|
|
||||||
|
prev_insert_offset = accessible->insert_offset;
|
||||||
|
prev_selection_bound = accessible->selection_bound;
|
||||||
|
|
||||||
|
gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer));
|
||||||
|
insert_offset = gtk_text_iter_get_offset (&iter);
|
||||||
|
gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_selection_bound (buffer));
|
||||||
|
selection_bound = gtk_text_iter_get_offset (&iter);
|
||||||
|
|
||||||
|
if (prev_insert_offset == insert_offset && prev_selection_bound == selection_bound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
accessible->insert_offset = insert_offset;
|
||||||
|
accessible->selection_bound = selection_bound;
|
||||||
|
|
||||||
|
if (prev_insert_offset != insert_offset)
|
||||||
|
g_signal_emit_by_name (accessible, "text-caret-moved", insert_offset);
|
||||||
|
|
||||||
|
if (prev_insert_offset != prev_selection_bound || insert_offset != selection_bound)
|
||||||
|
g_signal_emit_by_name (accessible, "text-selection-changed");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
insert_text_cb (GtkTextBuffer *buffer,
|
insert_text_cb (GtkTextBuffer *buffer,
|
||||||
GtkTextIter *iter,
|
GtkTextIter *iter,
|
||||||
@ -1176,33 +1183,12 @@ insert_text_cb (GtkTextBuffer *buffer,
|
|||||||
|
|
||||||
accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
|
accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
|
||||||
|
|
||||||
accessible->signal_name = "text_changed::insert";
|
|
||||||
position = gtk_text_iter_get_offset (iter);
|
position = gtk_text_iter_get_offset (iter);
|
||||||
length = g_utf8_strlen (text, len);
|
length = g_utf8_strlen (text, len);
|
||||||
|
|
||||||
if (accessible->length == 0)
|
g_signal_emit_by_name (accessible, "text-changed::insert", position - length, length);
|
||||||
{
|
|
||||||
accessible->position = position;
|
gtk_text_view_accessible_update_cursor (accessible, buffer);
|
||||||
accessible->length = length;
|
|
||||||
}
|
|
||||||
else if (accessible->position + accessible->length == position)
|
|
||||||
{
|
|
||||||
accessible->length += length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We have a non-contiguous insert so report what we have
|
|
||||||
*/
|
|
||||||
if (accessible->insert_notify_handler)
|
|
||||||
{
|
|
||||||
g_source_remove (accessible->insert_notify_handler);
|
|
||||||
}
|
|
||||||
accessible->insert_notify_handler = 0;
|
|
||||||
insert_idle_handler (accessible);
|
|
||||||
accessible->position = position;
|
|
||||||
accessible->length = length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1211,73 +1197,21 @@ delete_range_cb (GtkTextBuffer *buffer,
|
|||||||
GtkTextIter *end,
|
GtkTextIter *end,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
GtkTextView *text = data;
|
GtkTextView *view = data;
|
||||||
GtkTextViewAccessible *accessible;
|
GtkTextViewAccessible *accessible;
|
||||||
gint offset;
|
gint offset, length;
|
||||||
gint length;
|
|
||||||
|
|
||||||
|
accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view)));
|
||||||
|
|
||||||
offset = gtk_text_iter_get_offset (start);
|
offset = gtk_text_iter_get_offset (start);
|
||||||
length = gtk_text_iter_get_offset (end) - offset;
|
length = gtk_text_iter_get_offset (end) - offset;
|
||||||
|
|
||||||
accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
|
g_signal_emit_by_name (accessible,
|
||||||
if (accessible->insert_notify_handler)
|
"text_changed::delete",
|
||||||
{
|
offset,
|
||||||
g_source_remove (accessible->insert_notify_handler);
|
length);
|
||||||
accessible->insert_notify_handler = 0;
|
|
||||||
if (accessible->position == offset &&
|
|
||||||
accessible->length == length)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Do not bother with insert and delete notifications
|
|
||||||
*/
|
|
||||||
accessible->signal_name = NULL;
|
|
||||||
accessible->position = 0;
|
|
||||||
accessible->length = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
insert_idle_handler (accessible);
|
gtk_text_view_accessible_update_cursor (accessible, buffer);
|
||||||
}
|
|
||||||
g_signal_emit_by_name (accessible, "text_changed::delete", offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
get_selection_bound (GtkTextBuffer *buffer)
|
|
||||||
{
|
|
||||||
GtkTextMark *bound;
|
|
||||||
GtkTextIter iter;
|
|
||||||
|
|
||||||
bound = gtk_text_buffer_get_selection_bound (buffer);
|
|
||||||
gtk_text_buffer_get_iter_at_mark (buffer, &iter, bound);
|
|
||||||
return gtk_text_iter_get_offset (&iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
emit_text_caret_moved (GtkTextViewAccessible *accessible,
|
|
||||||
gint offset)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If we have text which has been inserted notify the user
|
|
||||||
*/
|
|
||||||
if (accessible->insert_notify_handler)
|
|
||||||
{
|
|
||||||
g_source_remove (accessible->insert_notify_handler);
|
|
||||||
accessible->insert_notify_handler = 0;
|
|
||||||
insert_idle_handler (accessible);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset != accessible->previous_insert_offset)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the caret position has not changed then don't bother notifying
|
|
||||||
*
|
|
||||||
* When mouse click is used to change caret position, notification
|
|
||||||
* is received on button down and button up.
|
|
||||||
*/
|
|
||||||
g_signal_emit_by_name (accessible, "text_caret_moved", offset);
|
|
||||||
accessible->previous_insert_offset = offset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1297,84 +1231,12 @@ mark_set_cb (GtkTextBuffer *buffer,
|
|||||||
*/
|
*/
|
||||||
if (mark == gtk_text_buffer_get_insert (buffer))
|
if (mark == gtk_text_buffer_get_insert (buffer))
|
||||||
{
|
{
|
||||||
gint insert_offset, selection_bound;
|
gtk_text_view_accessible_update_cursor (accessible, buffer);
|
||||||
gboolean selection_changed;
|
|
||||||
|
|
||||||
insert_offset = gtk_text_iter_get_offset (location);
|
|
||||||
|
|
||||||
selection_bound = get_selection_bound (buffer);
|
|
||||||
if (selection_bound != insert_offset)
|
|
||||||
{
|
|
||||||
if (selection_bound != accessible->previous_selection_bound ||
|
|
||||||
insert_offset != accessible->previous_insert_offset)
|
|
||||||
selection_changed = TRUE;
|
|
||||||
else
|
|
||||||
selection_changed = FALSE;
|
|
||||||
}
|
|
||||||
else if (accessible->previous_selection_bound != accessible->previous_insert_offset)
|
|
||||||
selection_changed = TRUE;
|
|
||||||
else
|
|
||||||
selection_changed = FALSE;
|
|
||||||
|
|
||||||
emit_text_caret_moved (accessible, insert_offset);
|
|
||||||
/*
|
|
||||||
* insert and selection_bound marks are different to a selection
|
|
||||||
* has changed
|
|
||||||
*/
|
|
||||||
if (selection_changed)
|
|
||||||
g_signal_emit_by_name (accessible, "text_selection_changed");
|
|
||||||
accessible->previous_selection_bound = selection_bound;
|
|
||||||
}
|
}
|
||||||
}
|
else if (mark == gtk_text_buffer_get_selection_bound (buffer))
|
||||||
|
|
||||||
static void
|
|
||||||
changed_cb (GtkTextBuffer *buffer,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
GtkTextView *text = data;
|
|
||||||
GtkTextViewAccessible *accessible;
|
|
||||||
|
|
||||||
accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text)));
|
|
||||||
if (accessible->signal_name)
|
|
||||||
{
|
{
|
||||||
if (!accessible->insert_notify_handler)
|
gtk_text_view_accessible_update_cursor (accessible, buffer);
|
||||||
{
|
|
||||||
accessible->insert_notify_handler = gdk_threads_add_idle (insert_idle_handler, accessible);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
emit_text_caret_moved (accessible, get_insert_offset (buffer));
|
|
||||||
accessible->previous_selection_bound = get_selection_bound (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
insert_idle_handler (gpointer data)
|
|
||||||
{
|
|
||||||
GtkTextViewAccessible *accessible = data;
|
|
||||||
GtkWidget *widget;
|
|
||||||
GtkTextBuffer *buffer;
|
|
||||||
|
|
||||||
g_signal_emit_by_name (data,
|
|
||||||
accessible->signal_name,
|
|
||||||
accessible->position,
|
|
||||||
accessible->length);
|
|
||||||
accessible->signal_name = NULL;
|
|
||||||
accessible->position = 0;
|
|
||||||
accessible->length = 0;
|
|
||||||
|
|
||||||
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
|
|
||||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
|
|
||||||
if (accessible->insert_notify_handler)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If called from idle handler notify caret moved
|
|
||||||
*/
|
|
||||||
accessible->insert_notify_handler = 0;
|
|
||||||
emit_text_caret_moved (accessible, get_insert_offset (buffer));
|
|
||||||
accessible->previous_selection_bound = get_selection_bound (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
|
|||||||
@ -38,16 +38,8 @@ struct _GtkTextViewAccessible
|
|||||||
{
|
{
|
||||||
GtkContainerAccessible parent;
|
GtkContainerAccessible parent;
|
||||||
|
|
||||||
gint previous_insert_offset;
|
gint insert_offset;
|
||||||
gint previous_selection_bound;
|
gint selection_bound;
|
||||||
/*
|
|
||||||
* These fields store information about text changed
|
|
||||||
*/
|
|
||||||
gchar *signal_name;
|
|
||||||
gint position;
|
|
||||||
gint length;
|
|
||||||
|
|
||||||
guint insert_notify_handler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GtkTextViewAccessibleClass
|
struct _GtkTextViewAccessibleClass
|
||||||
|
|||||||
Reference in New Issue
Block a user