1 /* ATK - Accessibility Toolkit
2 * Copyright 2001 Sun Microsystems Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <glib-object.h>
26 /* New GObject properties registered by AtkObject */
29 PROP_0, /* gobject convention */
33 PROP_PARENT, /* ancestry has changed */
34 PROP_CHILD, /* a child has been added or removed */
35 PROP_STATE, /* AtkStateSet for the object has changed */
36 PROP_TEXT, /* Used only by AtkText implementors */
37 PROP_CARET, /* Used only by AtkText implementors */
43 PROP_TABLE_COLUMN_DESCRIPTION,
44 PROP_TABLE_COLUMN_HEADER,
45 PROP_TABLE_ROW_DESCRIPTION,
46 PROP_TABLE_ROW_HEADER,
49 PROP_LAST /* gobject convention */
60 static void atk_object_class_init (AtkObjectClass *klass);
61 static void atk_object_init (AtkObject *accessible,
62 AtkObjectClass *klass);
63 static AtkRelationSet* atk_object_real_ref_relation_set
64 (AtkObject *accessible);
66 static void atk_object_real_set_property (GObject *object,
70 static void atk_object_real_get_property (GObject *object,
74 static void atk_object_finalize (GObject *object);
75 static G_CONST_RETURN gchar*
76 atk_object_real_get_name (AtkObject *object);
77 static G_CONST_RETURN gchar*
78 atk_object_real_get_description
80 static AtkObject* atk_object_real_get_parent (AtkObject *object);
81 static AtkRole atk_object_real_get_role (AtkObject *object);
82 static void atk_object_real_set_name (AtkObject *object,
84 static void atk_object_real_set_description
86 const gchar *description);
87 static void atk_object_real_set_parent (AtkObject *object,
89 static void atk_object_real_set_role (AtkObject *object,
91 static guint atk_object_real_connect_property_change_handler
93 AtkPropertyChangeHandler
95 static void atk_object_real_remove_property_change_handler
98 static void atk_object_notify (GObject *obj,
102 static guint atk_object_signals[LAST_SIGNAL] = { 0, };
104 static gpointer parent_class = NULL;
106 static const gchar* atk_object_name_property_name = "accessible-name";
107 static const gchar* atk_object_name_property_state = "accessible-state";
108 static const gchar* atk_object_name_property_description = "accessible-description";
109 static const gchar* atk_object_name_property_child = "accessible-child";
110 static const gchar* atk_object_name_property_parent = "accessible-parent";
111 static const gchar* atk_object_name_property_text = "accessible-text";
112 static const gchar* atk_object_name_property_caret = "accessible-caret";
113 static const gchar* atk_object_name_property_selection = "accessible-selection";
114 static const gchar* atk_object_name_property_value = "accessible-value";
115 static const gchar* atk_object_name_property_visible = "accessible-visible-data";
116 static const gchar* atk_object_name_property_role = "accessible-role";
117 static const gchar* atk_object_name_property_table_caption = "accessible-table-caption";
118 static const gchar* atk_object_name_property_table_column_description = "accessible-table-column-description";
119 static const gchar* atk_object_name_property_table_column_header = "accessible-table-column-header";
120 static const gchar* atk_object_name_property_table_row_description = "accessible-table-row-description";
121 static const gchar* atk_object_name_property_table_row_header = "accessible-table-row-header";
122 static const gchar* atk_object_name_property_table_summary = "accessible-table-summary";
123 static const gchar* atk_object_name_property_model = "accessible-model";
126 atk_object_get_type (void)
128 static GType type = 0;
132 static const GTypeInfo typeInfo =
134 sizeof (AtkObjectClass),
135 (GBaseInitFunc) NULL,
136 (GBaseFinalizeFunc) NULL,
137 (GClassInitFunc) atk_object_class_init,
138 (GClassFinalizeFunc) NULL,
142 (GInstanceInitFunc) atk_object_init,
144 type = g_type_register_static (G_TYPE_OBJECT, "AtkObject", &typeInfo, 0) ;
150 atk_object_class_init (AtkObjectClass *klass)
152 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
154 parent_class = g_type_class_ref (G_TYPE_OBJECT);
156 gobject_class->set_property = atk_object_real_set_property;
157 gobject_class->get_property = atk_object_real_get_property;
158 gobject_class->finalize = atk_object_finalize;
159 gobject_class->notify = atk_object_notify;
161 klass->get_name = atk_object_real_get_name;
162 klass->get_description = atk_object_real_get_description;
163 klass->get_parent = atk_object_real_get_parent;
164 klass->get_n_children = NULL;
165 klass->ref_child = NULL;
166 klass->get_index_in_parent = NULL;
167 klass->ref_relation_set = atk_object_real_ref_relation_set;
168 klass->get_role = atk_object_real_get_role;
169 klass->ref_state_set = NULL;
170 klass->set_name = atk_object_real_set_name;
171 klass->set_description = atk_object_real_set_description;
172 klass->set_parent = atk_object_real_set_parent;
173 klass->set_role = atk_object_real_set_role;
174 klass->connect_property_change_handler =
175 atk_object_real_connect_property_change_handler;
176 klass->remove_property_change_handler =
177 atk_object_real_remove_property_change_handler;
180 * We do not define default signal handlers here
182 klass->children_changed = NULL;
183 klass->focus_event = NULL;
184 klass->property_change = NULL;
186 g_object_class_install_property (gobject_class,
188 g_param_spec_string (atk_object_name_property_name,
190 "Object instance\'s name formatted for "
191 "assistive technology access",
194 g_object_class_install_property (gobject_class,
196 g_param_spec_string (atk_object_name_property_description,
197 "Accessible Description",
198 "Description of an object, formatted for "
199 "assistive technology access",
202 g_object_class_install_property (gobject_class,
204 g_param_spec_int (atk_object_name_property_state,
205 "Accessible State Set",
206 "The accessible state set of this object "
207 "or its UI component",
212 g_object_class_install_property (gobject_class,
214 g_param_spec_object (atk_object_name_property_child,
216 "Is used to notify that a child has been added or removed ",
219 g_object_class_install_property (gobject_class,
221 g_param_spec_object (atk_object_name_property_parent,
223 "Is used to notify that the parent has changed ",
226 g_object_class_install_property (gobject_class,
228 g_param_spec_object (atk_object_name_property_text,
230 "Is used to notify that the text has changed ",
233 g_object_class_install_property (gobject_class,
235 g_param_spec_int (atk_object_name_property_caret,
237 "Is used to notify that the caret position has changed ",
242 g_object_class_install_property (gobject_class,
244 g_param_spec_object (atk_object_name_property_selection,
245 "Accessible Selection",
246 "Is used to notify that the selection has changed ",
249 g_object_class_install_property (gobject_class,
251 g_param_spec_double (atk_object_name_property_value,
253 "Is used to notify that the value has changed ",
258 g_object_class_install_property (gobject_class,
260 g_param_spec_object (atk_object_name_property_visible,
261 "Accessible Visible Data",
262 "Is used to notify that the visual appearance of the object has changed ",
265 g_object_class_install_property (gobject_class,
267 g_param_spec_int (atk_object_name_property_role,
269 "The accessible role this object ",
274 g_object_class_install_property (gobject_class,
276 g_param_spec_object (atk_object_name_property_table_caption,
277 "Accessible Table Caption",
278 "Is used to notify that the table caption has changed ",
281 g_object_class_install_property (gobject_class,
282 PROP_TABLE_COLUMN_HEADER,
283 g_param_spec_object (atk_object_name_property_table_column_header,
284 "Accessible Table Column Header",
285 "Is used to notify that the table column header has changed ",
288 g_object_class_install_property (gobject_class,
289 PROP_TABLE_COLUMN_DESCRIPTION,
290 g_param_spec_int (atk_object_name_property_table_column_description,
291 "Accessible Table Column Description",
292 "Is used to notify that the table columnscription has changed ",
297 g_object_class_install_property (gobject_class,
298 PROP_TABLE_ROW_HEADER,
299 g_param_spec_object (atk_object_name_property_table_row_header,
300 "Accessible Table Row Header",
301 "Is used to notify that the table row header has changed ",
304 g_object_class_install_property (gobject_class,
305 PROP_TABLE_ROW_DESCRIPTION,
306 g_param_spec_int (atk_object_name_property_table_row_description,
307 "Accessible Table Row Description",
308 "Is used to notify that the table row description has changed ",
313 g_object_class_install_property (gobject_class,
315 g_param_spec_object (atk_object_name_property_table_summary,
316 "Accessible Table Summary",
317 "Is used to notify that the table summary has changed ",
320 g_object_class_install_property (gobject_class,
322 g_param_spec_object (atk_object_name_property_model,
324 "Is used to notify that the model for Table or Tree has changed ",
328 * The signal "children_changed" supports two details:
331 atk_object_signals[CHILDREN_CHANGED] =
332 g_signal_new ("children_changed",
333 G_TYPE_FROM_CLASS (klass),
334 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
335 G_STRUCT_OFFSET (AtkObjectClass, children_changed),
337 g_cclosure_marshal_VOID__UINT_POINTER,
339 2, G_TYPE_UINT, G_TYPE_POINTER);
340 atk_object_signals[FOCUS_EVENT] =
341 g_signal_new ("focus_event",
342 G_TYPE_FROM_CLASS (klass),
344 G_STRUCT_OFFSET (AtkObjectClass, focus_event),
346 g_cclosure_marshal_VOID__BOOLEAN,
349 atk_object_signals[PROPERTY_CHANGE] =
350 g_signal_new ("property_change",
351 G_TYPE_FROM_CLASS (klass),
353 G_STRUCT_OFFSET (AtkObjectClass, property_change),
354 (GSignalAccumulator) NULL, NULL,
355 g_cclosure_marshal_VOID__POINTER,
361 atk_object_init (AtkObject *accessible,
362 AtkObjectClass *klass)
364 accessible->name = NULL;
365 accessible->description = NULL;
366 accessible->accessible_parent = NULL;
367 accessible->relation_set = NULL;
368 accessible->role = ATK_ROLE_UNKNOWN;
372 atk_implementor_get_type (void)
374 static GType type = 0;
378 static const GTypeInfo typeInfo =
380 sizeof (AtkImplementorIface),
381 (GBaseInitFunc) NULL,
382 (GBaseFinalizeFunc) NULL,
385 type = g_type_register_static (G_TYPE_INTERFACE, "AtkImplementorIface", &typeInfo, 0) ;
392 * atk_object_get_name:
393 * @accessible: an #AtkObject
395 * Gets the accessible name of the accessible.
397 * Returns: a character string representing the accessible name of the object.
399 G_CONST_RETURN gchar*
400 atk_object_get_name (AtkObject *accessible)
402 AtkObjectClass *klass;
404 g_return_val_if_fail (accessible != NULL, NULL);
405 g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
407 klass = ATK_OBJECT_GET_CLASS (accessible);
409 return (klass->get_name) (accessible);
415 * atk_object_get_description:
416 * @accessible: an #AtkObject
418 * Gets the accessible description of the accessible.
420 * Returns: a character string representing the accessible description
424 G_CONST_RETURN gchar*
425 atk_object_get_description (AtkObject *accessible)
427 AtkObjectClass *klass;
429 g_return_val_if_fail (accessible != NULL, NULL);
430 g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
432 klass = ATK_OBJECT_GET_CLASS (accessible);
433 if (klass->get_description)
434 return (klass->get_description) (accessible);
440 * atk_object_get_parent:
441 * @accessible: an #AtkObject
443 * Gets the accessible parent of the accessible.
445 * Returns: a #AtkObject representing the accessible parent of the accessible
448 atk_object_get_parent (AtkObject *accessible)
450 AtkObjectClass *klass;
452 g_return_val_if_fail (accessible != NULL, NULL);
453 g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
455 klass = ATK_OBJECT_GET_CLASS (accessible);
456 if (klass->get_parent)
457 return (klass->get_parent) (accessible);
463 * atk_object_get_n_accessible_children:
464 * @accessible: an #AtkObject
466 * Gets the number of accessible children of the accessible.
468 * Returns: an integer representing the number of accessible children
472 atk_object_get_n_accessible_children (AtkObject *accessible)
474 AtkObjectClass *klass;
476 g_return_val_if_fail (accessible != NULL, 0);
477 g_return_val_if_fail (ATK_IS_OBJECT (accessible), 0);
479 klass = ATK_OBJECT_GET_CLASS (accessible);
480 if (klass->get_n_children)
481 return (klass->get_n_children) (accessible);
487 * atk_object_ref_accessible_child:
488 * @accessible: an #AtkObject
489 * @i: a gint representing the position of the child, starting from 0
491 * Gets a reference to the specified accessible child of the object.
492 * The accessible children are 0-based so the first accessible child is
493 * at index 0, the second at index 1 and so on.
495 * Returns: an #AtkObject representing the specified accessible child
499 atk_object_ref_accessible_child (AtkObject *accessible,
502 AtkObjectClass *klass;
504 g_return_val_if_fail (accessible != NULL, NULL);
505 g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
507 klass = ATK_OBJECT_GET_CLASS (accessible);
508 if (klass->ref_child)
509 return (klass->ref_child) (accessible, i);
515 * atk_object_ref_relation_set:
516 * @accessible: an #AtkObject
518 * Gets the #AtkRelationSet associated with the object.
520 * Returns: an #AtkRelationSet representing the relation set of the object.
523 atk_object_ref_relation_set (AtkObject *accessible)
525 AtkObjectClass *klass;
527 g_return_val_if_fail (accessible != NULL, NULL);
528 g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
530 klass = ATK_OBJECT_GET_CLASS (accessible);
531 if (klass->ref_relation_set)
532 return (klass->ref_relation_set) (accessible);
539 * @name: a character string describing the new role.
541 * Registers the role specified by @name.
543 * Returns: an #AtkRole for the new role.
546 atk_role_register (const gchar *name)
548 /* TODO: associate name with new type */
549 static guint type = ATK_ROLE_LAST_DEFINED;
554 * atk_object_get_role:
555 * @accessible: an #AtkObject
557 * Gets the role of the accessible.
559 * Returns: an #AtkRole which is the role of the accessible
562 atk_object_get_role (AtkObject *accessible) {
563 AtkObjectClass *klass;
565 g_return_val_if_fail (accessible != NULL, ATK_ROLE_UNKNOWN);
566 g_return_val_if_fail (ATK_IS_OBJECT (accessible), ATK_ROLE_UNKNOWN);
568 klass = ATK_OBJECT_GET_CLASS (accessible);
570 return (klass->get_role) (accessible);
572 return ATK_ROLE_UNKNOWN;
576 * atk_object_ref_state_set:
577 * @accessible: an #AtkObject
579 * Gets a reference to the state set of the accessible; the caller must
580 * unreference it when it is no longer needed.
582 * Returns: a reference to an #AtkStateSet which is the state
583 * set of the accessible
586 atk_object_ref_state_set (AtkObject *accessible) {
587 AtkObjectClass *klass;
589 g_return_val_if_fail (accessible != NULL, NULL);
590 g_return_val_if_fail (ATK_IS_OBJECT (accessible), NULL);
592 klass = ATK_OBJECT_GET_CLASS (accessible);
593 if (klass->ref_state_set)
594 return (klass->ref_state_set) (accessible);
600 * atk_object_get_index_in_parent:
601 * @accessible: an #AtkObject
603 * Gets the 0-based index of this accessible in its parent; returns -1 if the
604 * accessible does not have an accessible parent.
606 * Returns: an integer which is the index of the accessible in its parent
609 atk_object_get_index_in_parent (AtkObject *accessible)
611 AtkObjectClass *klass;
613 g_return_val_if_fail (accessible != NULL, -1);
614 g_return_val_if_fail (ATK_OBJECT (accessible), -1);
616 klass = ATK_OBJECT_GET_CLASS (accessible);
617 if (klass->get_index_in_parent)
618 return (klass->get_index_in_parent) (accessible);
624 * atk_object_set_name:
625 * @accessible: an #AtkObject
626 * @name: a character string to be set as the accessible name
628 * Sets the accessible name of the accessible.
631 atk_object_set_name (AtkObject *accessible,
634 AtkObjectClass *klass;
636 g_return_if_fail (accessible != NULL);
637 g_return_if_fail (ATK_IS_OBJECT (accessible));
638 g_return_if_fail (name != NULL);
640 klass = ATK_OBJECT_GET_CLASS (accessible);
643 (klass->set_name) (accessible, name);
644 g_object_notify (G_OBJECT (accessible), atk_object_name_property_name);
649 * atk_object_set_description:
650 * @accessible: an #AtkObject
651 * @description : a character string to be set as the accessible description
653 * Sets the accessible description of the accessible.
656 atk_object_set_description (AtkObject *accessible,
657 const gchar *description)
659 AtkObjectClass *klass;
661 g_return_if_fail (accessible != NULL);
662 g_return_if_fail (ATK_IS_OBJECT (accessible));
663 g_return_if_fail (description != NULL);
665 klass = ATK_OBJECT_GET_CLASS (accessible);
666 if (klass->set_description)
668 (klass->set_description) (accessible, description);
669 g_object_notify (G_OBJECT (accessible), atk_object_name_property_description);
674 * atk_object_set_parent:
675 * @accessible: an #AtkObject
676 * @parent : an #AtkObject to be set as the accessible parent
678 * Sets the accessible parent of the accessible.
681 atk_object_set_parent (AtkObject *accessible,
684 AtkObjectClass *klass;
686 g_return_if_fail (accessible != NULL);
687 g_return_if_fail (ATK_IS_OBJECT (accessible));
689 klass = ATK_OBJECT_GET_CLASS (accessible);
690 if (klass->set_parent)
691 (klass->set_parent) (accessible, parent);
695 * atk_object_set_role:
696 * @accessible: an #AtkObject
697 * @role : an #AtkRole to be set as the role
699 * Sets the role of the accessible.
702 atk_object_set_role (AtkObject *accessible,
705 AtkObjectClass *klass;
707 g_return_if_fail (accessible != NULL);
708 g_return_if_fail (ATK_IS_OBJECT (accessible));
710 klass = ATK_OBJECT_GET_CLASS (accessible);
712 (klass->set_role) (accessible, role);
716 * atk_object_connect_property_change_handler:
717 * @accessible: an #AtkObject
718 * @handler : a function to be called when a property changes its value
720 * Specifies a function to be called when a property changes value.
722 * Returns: a #guint which is the handler id used in
723 * atk_object_remove_property_change_handler()
726 atk_object_connect_property_change_handler (AtkObject *accessible,
727 AtkPropertyChangeHandler *handler)
729 AtkObjectClass *klass;
731 g_return_val_if_fail (accessible != NULL, 0);
732 g_return_val_if_fail (ATK_IS_OBJECT (accessible), 0);
733 g_return_val_if_fail ((handler != NULL), 0);
735 klass = ATK_OBJECT_GET_CLASS (accessible);
736 if (klass->connect_property_change_handler)
737 return (klass->connect_property_change_handler) (accessible, handler);
743 * atk_object_remove_property_change_handler:
744 * @accessible: an #AtkObject
745 * @handler_id : a guint which identifies the handler to be removed.
747 * Removes a property change handler.
750 atk_object_remove_property_change_handler (AtkObject *accessible,
753 AtkObjectClass *klass;
755 g_return_if_fail (accessible != NULL);
756 g_return_if_fail (ATK_IS_OBJECT (accessible));
758 klass = ATK_OBJECT_GET_CLASS (accessible);
759 if (klass->remove_property_change_handler)
760 (klass->remove_property_change_handler) (accessible, handler_id);
764 * atk_implementor_ref_accessible:
765 * @implementor: The #GObject instance which should implement #AtkImplementorIface
766 * if a non-null return value is required.
768 * Gets a reference to an object's #AtkObject implementation, if
769 * the object implements #AtkObjectIface
771 * Returns: a reference to an object's #AtkObject implementation
774 atk_implementor_ref_accessible (AtkImplementor *object)
776 AtkImplementorIface *iface;
777 AtkObject *accessible = NULL;
779 g_return_val_if_fail (object != NULL, NULL);
780 g_return_val_if_fail (ATK_IS_IMPLEMENTOR (object), NULL);
782 iface = ATK_IMPLEMENTOR_GET_IFACE (object);
785 accessible = iface->ref_accessible (object);
787 g_return_val_if_fail ((accessible != NULL), NULL);
792 static AtkRelationSet*
793 atk_object_real_ref_relation_set (AtkObject *accessible)
795 if (accessible->relation_set)
796 g_object_ref (accessible->relation_set);
798 return accessible->relation_set;
802 atk_object_real_set_property (GObject *object,
807 AtkObject *accessible;
809 accessible = ATK_OBJECT (object);
814 atk_object_set_name (accessible, g_value_get_string (value));
816 case PROP_DESCRIPTION:
817 atk_object_set_description (accessible, g_value_get_string (value));
820 g_print ("This interface does not support setting the state set of an accessible object\n");
823 if (ATK_IS_VALUE (accessible))
824 atk_value_set_current_value (ATK_VALUE (accessible), value);
832 atk_object_real_get_property (GObject *object,
837 AtkObject *accessible;
839 accessible = ATK_OBJECT (object);
844 g_value_set_string (value, atk_object_get_name (accessible));
846 case PROP_DESCRIPTION:
847 g_value_set_string (value, atk_object_get_description (accessible));
850 if (ATK_IS_VALUE (accessible))
851 atk_value_get_current_value (ATK_VALUE (accessible), value);
859 atk_object_finalize (GObject *object)
861 AtkObject *accessible;
863 g_return_if_fail (ATK_IS_OBJECT (object));
865 accessible = ATK_OBJECT (object);
867 g_free (accessible->name);
868 g_free (accessible->description);
871 * Free memory allocated for relation set if it have been allocated.
873 if (accessible->relation_set)
875 g_object_unref (accessible->relation_set);
878 G_OBJECT_CLASS (parent_class)->finalize (object);
881 static G_CONST_RETURN gchar*
882 atk_object_real_get_name (AtkObject *object)
887 static G_CONST_RETURN gchar*
888 atk_object_real_get_description (AtkObject *object)
890 return object->description;
894 atk_object_real_get_parent (AtkObject *object)
896 return object->accessible_parent;
900 atk_object_real_get_role (AtkObject *object)
906 atk_object_real_set_name (AtkObject *object,
909 g_free (object->name);
910 object->name = g_strdup (name);
914 atk_object_real_set_description (AtkObject *object,
915 const gchar *description)
917 g_free (object->description);
918 object->description = g_strdup (description);
922 atk_object_real_set_parent (AtkObject *object,
925 object->accessible_parent = parent;
930 atk_object_real_set_role (AtkObject *object,
937 atk_object_real_connect_property_change_handler (AtkObject *obj,
938 AtkPropertyChangeHandler *handler)
940 return g_signal_connect_closure_by_id (obj,
941 atk_object_signals[PROPERTY_CHANGE],
944 G_CALLBACK (handler), NULL,
945 (GClosureNotify) NULL),
950 atk_object_real_remove_property_change_handler (AtkObject *obj,
953 g_signal_handler_disconnect (obj, handler_id);
957 * This function is a signal handler for notify signal which gets emitted
958 * when a property changes value.
960 * It constructs an AtkPropertyValues structure and emits a "property_changed"
961 * signal which causes the user specified AtkPropertyChangeHandler
965 atk_object_notify (GObject *obj,
968 AtkPropertyValues values;
970 memset (&values.old_value, 0, sizeof (GValue));
971 memset (&values.new_value, 0, sizeof (GValue));
972 g_value_init (&values.new_value, pspec->value_type);
973 g_object_get_property(obj, pspec->name, &values.new_value);
974 values.property_name = pspec->name;
975 g_signal_emit (obj, atk_object_signals[PROPERTY_CHANGE], 0,