From 86802b3155315d28c062ceb19b826846f78169e4 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 22 Feb 2022 11:12:26 +1300 Subject: [PATCH] Fix signals adding/removing a11y nodes in Linux. Previously each time a node changed all its children were being notified as being added. No signals were being generated for removed nodes. --- shell/platform/linux/fl_accessible_node.cc | 31 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/fl_accessible_node.cc b/shell/platform/linux/fl_accessible_node.cc index 21cdb24de985a..a65d77963cf1c 100644 --- a/shell/platform/linux/fl_accessible_node.cc +++ b/shell/platform/linux/fl_accessible_node.cc @@ -118,6 +118,17 @@ static ActionData* get_action(FlAccessibleNode* self, gint index) { return static_cast(g_ptr_array_index(self->actions, index)); } +// Checks if [object] is in [children]. +static gboolean has_child(GPtrArray* children, AtkObject* object) { + for (guint i = 0; i < children->len; i++) { + if (g_ptr_array_index(children, i) == object) { + return TRUE; + } + } + + return FALSE; +} + static void fl_accessible_node_dispose(GObject* object) { FlAccessibleNode* self = FL_ACCESSIBLE_NODE(object); @@ -330,11 +341,25 @@ void fl_accessible_node_set_children(FlAccessibleNode* self, GPtrArray* children) { g_return_if_fail(FL_IS_ACCESSIBLE_NODE(self)); - g_ptr_array_remove_range(self->children, 0, self->children->len); + // Remove nodes that are no longer required. + for (guint i = 0; i < self->children->len;) { + AtkObject* object = ATK_OBJECT(g_ptr_array_index(self->children, i)); + if (has_child(children, object)) { + i++; + } else { + g_signal_emit_by_name(self, "children-changed::remove", i, object, + nullptr); + g_ptr_array_remove_index(self->children, i); + } + } + + // Add new nodes. for (guint i = 0; i < children->len; i++) { AtkObject* object = ATK_OBJECT(g_ptr_array_index(children, i)); - g_ptr_array_add(self->children, g_object_ref(object)); - g_signal_emit_by_name(self, "children-changed::add", i, object, nullptr); + if (!has_child(self->children, object)) { + g_ptr_array_add(self->children, g_object_ref(object)); + g_signal_emit_by_name(self, "children-changed::add", i, object, nullptr); + } } }