Flutter Linux Embedder
fl_view_accessible.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
10 
12  GtkContainerAccessible parent_instance;
13 
14  FlEngine* engine;
15 
16  // Semantics nodes keyed by ID
17  GHashTable* semantics_nodes_by_id;
18 
19  // Child IDs stored until commit_updates is called
20  GHashTable* pending_children;
21 };
22 
24 
25 G_DEFINE_TYPE(FlViewAccessible,
26  fl_view_accessible,
27  GTK_TYPE_CONTAINER_ACCESSIBLE)
28 
29 static void init_engine(FlViewAccessible* self, FlEngine* engine) {
30  g_assert(self->engine == nullptr);
31  self->engine = engine;
32  g_object_add_weak_pointer(G_OBJECT(self),
33  reinterpret_cast<gpointer*>(&self->engine));
34 }
35 
36 static FlEngine* get_engine(FlViewAccessible* self) {
37  if (self->engine == nullptr) {
38  FlView* view = FL_VIEW(gtk_accessible_get_widget(GTK_ACCESSIBLE(self)));
39  init_engine(self, fl_view_get_engine(view));
40  }
41  return self->engine;
42 }
43 
44 static FlAccessibleNode* create_node(FlViewAccessible* self,
45  const FlutterSemanticsNode* semantics) {
46  FlEngine* engine = get_engine(self);
47 
48  if (semantics->flags & kFlutterSemanticsFlagIsTextField) {
49  return fl_accessible_text_field_new(engine, semantics->id);
50  }
51 
52  return fl_accessible_node_new(engine, semantics->id);
53 }
54 
55 static FlAccessibleNode* lookup_node(FlViewAccessible* self, int32_t id) {
56  return FL_ACCESSIBLE_NODE(
57  g_hash_table_lookup(self->semantics_nodes_by_id, GINT_TO_POINTER(id)));
58 }
59 
60 // Gets the ATK node for the given id.
61 // If the node doesn't exist it will be created.
62 static FlAccessibleNode* get_node(FlViewAccessible* self,
63  const FlutterSemanticsNode* semantics) {
64  FlAccessibleNode* node = lookup_node(self, semantics->id);
65  if (node != nullptr) {
66  return node;
67  }
68 
69  node = create_node(self, semantics);
70  if (semantics->id == 0) {
71  fl_accessible_node_set_parent(node, ATK_OBJECT(self), 0);
72  g_signal_emit_by_name(self, "children-changed::add", 0, node, nullptr);
73  }
74  g_hash_table_insert(self->semantics_nodes_by_id,
75  GINT_TO_POINTER(semantics->id),
76  reinterpret_cast<gpointer>(node));
77 
78  return node;
79 }
80 
81 static void commit_updates(FlViewAccessible* self) {
82  g_hash_table_foreach_remove(
83  self->pending_children,
84  [](gpointer key, gpointer value, gpointer user_data) -> gboolean {
85  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(user_data);
86 
87  FlAccessibleNode* parent = FL_ACCESSIBLE_NODE(key);
88 
89  size_t child_count = fl_value_get_length(static_cast<FlValue*>(value));
90  const int32_t* children_in_traversal_order =
91  fl_value_get_int32_list(static_cast<FlValue*>(value));
92 
93  g_autoptr(GPtrArray) children = g_ptr_array_new();
94  for (size_t i = 0; i < child_count; i++) {
95  FlAccessibleNode* child =
96  lookup_node(self, children_in_traversal_order[i]);
97  g_assert(child != nullptr);
98  fl_accessible_node_set_parent(child, ATK_OBJECT(parent), i);
99  g_ptr_array_add(children, child);
100  }
101  fl_accessible_node_set_children(parent, children);
102 
103  return true;
104  },
105  self);
106 }
107 
108 // Implements AtkObject::get_n_children
109 static gint fl_view_accessible_get_n_children(AtkObject* accessible) {
110  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(accessible);
111  FlAccessibleNode* node = lookup_node(self, 0);
112 
113  if (node == nullptr) {
114  return 0;
115  }
116 
117  return 1;
118 }
119 
120 // Implements AtkObject::ref_child
121 static AtkObject* fl_view_accessible_ref_child(AtkObject* accessible, gint i) {
122  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(accessible);
123  FlAccessibleNode* node = lookup_node(self, 0);
124 
125  if (i != 0 || node == nullptr) {
126  return nullptr;
127  }
128 
129  return ATK_OBJECT(g_object_ref(node));
130 }
131 
132 // Implements AtkObject::get_role
133 static AtkRole fl_view_accessible_get_role(AtkObject* accessible) {
134  return ATK_ROLE_PANEL;
135 }
136 
137 // Implements GObject::set_property
138 static void fl_view_accessible_set_property(GObject* object,
139  guint prop_id,
140  const GValue* value,
141  GParamSpec* pspec) {
142  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(object);
143  switch (prop_id) {
144  case kPropEngine:
145  init_engine(self, FL_ENGINE(g_value_get_object(value)));
146  break;
147  default:
148  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
149  break;
150  }
151 }
152 
153 static void fl_view_accessible_dispose(GObject* object) {
154  FlViewAccessible* self = FL_VIEW_ACCESSIBLE(object);
155 
156  g_clear_pointer(&self->semantics_nodes_by_id, g_hash_table_unref);
157  g_clear_pointer(&self->pending_children, g_hash_table_unref);
158 
159  if (self->engine != nullptr) {
160  g_object_remove_weak_pointer(object,
161  reinterpret_cast<gpointer*>(&self->engine));
162  self->engine = nullptr;
163  }
164 
165  G_OBJECT_CLASS(fl_view_accessible_parent_class)->dispose(object);
166 }
167 
168 static void fl_view_accessible_class_init(FlViewAccessibleClass* klass) {
169  ATK_OBJECT_CLASS(klass)->get_n_children = fl_view_accessible_get_n_children;
170  ATK_OBJECT_CLASS(klass)->ref_child = fl_view_accessible_ref_child;
171  ATK_OBJECT_CLASS(klass)->get_role = fl_view_accessible_get_role;
172 
173  G_OBJECT_CLASS(klass)->dispose = fl_view_accessible_dispose;
174  G_OBJECT_CLASS(klass)->set_property = fl_view_accessible_set_property;
175 
176  g_object_class_install_property(
177  G_OBJECT_CLASS(klass), kPropEngine,
178  g_param_spec_object(
179  "engine", "engine", "Flutter engine", fl_engine_get_type(),
180  static_cast<GParamFlags>(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
181  G_PARAM_STATIC_STRINGS)));
182 }
183 
184 static void fl_view_accessible_init(FlViewAccessible* self) {
185  self->semantics_nodes_by_id = g_hash_table_new_full(
186  g_direct_hash, g_direct_equal, nullptr, g_object_unref);
187  self->pending_children =
188  g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr,
189  reinterpret_cast<GDestroyNotify>(fl_value_unref));
190 }
191 
193  FlViewAccessible* self,
194  const FlutterSemanticsNode* node) {
195  if (node->id == kFlutterSemanticsNodeIdBatchEnd) {
196  commit_updates(self);
197  return;
198  }
199 
200  FlAccessibleNode* atk_node = get_node(self, node);
201 
202  fl_accessible_node_set_flags(atk_node, node->flags);
203  fl_accessible_node_set_actions(atk_node, node->actions);
204  fl_accessible_node_set_name(atk_node, node->label);
206  atk_node, node->rect.left + node->transform.transX,
207  node->rect.top + node->transform.transY,
208  node->rect.right - node->rect.left, node->rect.bottom - node->rect.top);
209  fl_accessible_node_set_value(atk_node, node->value);
210  fl_accessible_node_set_text_selection(atk_node, node->text_selection_base,
211  node->text_selection_extent);
212  fl_accessible_node_set_text_direction(atk_node, node->text_direction);
213 
214  FlValue* children = fl_value_new_int32_list(node->children_in_traversal_order,
215  node->child_count);
216  g_hash_table_insert(self->pending_children, atk_node, children);
217 }
fl_view_accessible.h
create_node
static FlAccessibleNode * create_node(FlViewAccessible *self, const FlutterSemanticsNode *semantics)
Definition: fl_view_accessible.cc:44
fl_accessible_node_set_text_selection
void fl_accessible_node_set_text_selection(FlAccessibleNode *self, gint base, gint extent)
Definition: fl_accessible_node.cc:562
fl_view_accessible_ref_child
static AtkObject * fl_view_accessible_ref_child(AtkObject *accessible, gint i)
Definition: fl_view_accessible.cc:121
fl_accessible_node_set_flags
void fl_accessible_node_set_flags(FlAccessibleNode *self, FlutterSemanticsFlag flags)
Definition: fl_accessible_node.cc:542
fl_accessible_node_set_parent
void fl_accessible_node_set_parent(FlAccessibleNode *self, AtkObject *parent, gint index)
Definition: fl_accessible_node.cc:487
fl_accessible_text_field_new
FlAccessibleNode * fl_accessible_text_field_new(FlEngine *engine, int32_t id)
Definition: fl_accessible_text_field.cc:618
_FlViewAccessible::engine
FlEngine * engine
Definition: fl_view_accessible.cc:14
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:40
user_data
FlKeyEvent uint64_t FlKeyResponderAsyncCallback gpointer user_data
Definition: fl_key_channel_responder.cc:121
_FlViewAccessible::semantics_nodes_by_id
GHashTable * semantics_nodes_by_id
Definition: fl_view_accessible.cc:17
fl_view_accessible_handle_update_semantics_node
void fl_view_accessible_handle_update_semantics_node(FlViewAccessible *self, const FlutterSemanticsNode *node)
Definition: fl_view_accessible.cc:192
fl_accessible_node_set_children
void fl_accessible_node_set_children(FlAccessibleNode *self, GPtrArray *children)
Definition: fl_accessible_node.cc:498
fl_view_accessible_init
static void fl_view_accessible_init(FlViewAccessible *self)
Definition: fl_view_accessible.cc:184
_FlViewAccessible::pending_children
GHashTable * pending_children
Definition: fl_view_accessible.cc:20
fl_value_unref
G_MODULE_EXPORT void fl_value_unref(FlValue *self)
Definition: fl_value.cc:369
fl_view_accessible_dispose
static void fl_view_accessible_dispose(GObject *object)
Definition: fl_view_accessible.cc:153
fl_view_accessible_set_property
static void fl_view_accessible_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Definition: fl_view_accessible.cc:138
kProp0
@ kProp0
Definition: fl_view_accessible.cc:23
get_node
static FlAccessibleNode * get_node(FlViewAccessible *self, const FlutterSemanticsNode *semantics)
Definition: fl_view_accessible.cc:62
fl_accessible_node_set_extents
void fl_accessible_node_set_extents(FlAccessibleNode *self, gint x, gint y, gint width, gint height)
Definition: fl_accessible_node.cc:531
kPropEngine
@ kPropEngine
Definition: fl_view_accessible.cc:23
fl_accessible_node_set_text_direction
void fl_accessible_node_set_text_direction(FlAccessibleNode *self, FlutterTextDirection direction)
Definition: fl_accessible_node.cc:571
fl_view_get_engine
G_MODULE_EXPORT FlEngine * fl_view_get_engine(FlView *self)
Definition: fl_view.cc:744
fl_accessible_node_set_value
void fl_accessible_node_set_value(FlAccessibleNode *self, const gchar *value)
Definition: fl_accessible_node.cc:556
fl_value_new_int32_list
G_MODULE_EXPORT FlValue * fl_value_new_int32_list(const int32_t *data, size_t data_length)
Definition: fl_value.cc:298
g_object_add_weak_pointer
g_object_add_weak_pointer(G_OBJECT(self), reinterpret_cast< gpointer * >(&self->engine))
fl_accessible_node.h
fl_accessible_node_new
FlAccessibleNode * fl_accessible_node_new(FlEngine *engine, int32_t id)
Definition: fl_accessible_node.cc:481
fl_view.h
G_DEFINE_TYPE
G_DEFINE_TYPE(FlViewAccessible, fl_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE) static void init_engine(FlViewAccessible *self
get_engine
static FlEngine * get_engine(FlViewAccessible *self)
Definition: fl_view_accessible.cc:36
self
GdkEvent FlView * self
Definition: fl_view.cc:100
_FlViewAccessible
Definition: fl_view_accessible.cc:11
kPropLast
@ kPropLast
Definition: fl_view_accessible.cc:23
fl_accessible_text_field.h
commit_updates
static void commit_updates(FlViewAccessible *self)
Definition: fl_view_accessible.cc:81
fl_view_accessible_get_n_children
static gint fl_view_accessible_get_n_children(AtkObject *accessible)
Definition: fl_view_accessible.cc:109
fl_value.h
_FlViewAccessible::parent_instance
GtkContainerAccessible parent_instance
Definition: fl_view_accessible.cc:12
engine
FlEngine * engine
Definition: fl_view_accessible.cc:29
fl_accessible_node_set_name
void fl_accessible_node_set_name(FlAccessibleNode *self, const gchar *name)
Definition: fl_accessible_node.cc:525
fl_accessible_node_set_actions
void fl_accessible_node_set_actions(FlAccessibleNode *self, FlutterSemanticsAction actions)
Definition: fl_accessible_node.cc:549
value
uint8_t value
Definition: fl_standard_message_codec.cc:41
lookup_node
static FlAccessibleNode * lookup_node(FlViewAccessible *self, int32_t id)
Definition: fl_view_accessible.cc:55
node
G_BEGIN_DECLS const FlutterSemanticsNode * node
Definition: fl_view_accessible.h:40
fl_view_accessible_get_role
static AtkRole fl_view_accessible_get_role(AtkObject *accessible)
Definition: fl_view_accessible.cc:133
fl_view_accessible_class_init
static void fl_view_accessible_class_init(FlViewAccessibleClass *klass)
Definition: fl_view_accessible.cc:168