diff --git a/docs/reference/gtk/section-accessibility.md b/docs/reference/gtk/section-accessibility.md index c86eb3c3c1..b86aac419b 100644 --- a/docs/reference/gtk/section-accessibility.md +++ b/docs/reference/gtk/section-accessibility.md @@ -292,12 +292,36 @@ The power of hiding and enhancing can be a double-edged sword, as it can lead to inadvertently overriding the accessible semantics of existing widgets. +## Hiding UI elements from the accessible tree + +The accessibility API is mainly used to express semantics useful for +assistive technologies, but it can also be used to hide elements. The +canonical way to do so is to use the %GTK_ACCESSIBLE_ROLE_PRESENTATION, +which declares that a UI element is purely meant for presentation purposes, +and as such it has no meaningful impact on the accessibility of the +interface. + +A "presentation" role should not be confused with the +%GTK_ACCESSIBLE_STATE_HIDDEN state; the "hidden" state is transient, and is +typically controlled by showing and hiding a widget using the #GtkWidget +API. + ## Design patterns and custom widgets When creating custom widgets, following established patterns can help ensuring that the widgets work well for users of accessible technologies as well. +### Buttons + +A button is a widget that enables users to trigger an action. While it is +recommended you use #GtkButton for anything that looks and behaves like a +button, it is possible to apply a button behavior to UI elements like images +by using a #GtkGestureClick gesture. When doing so, you should: + + - Give your widget the role %GTK_ACCESSIBLE_ROLE_BUTTON + - Install an action with no parameters, which will activate the widget + ### Custom entries For custom entries, it is highly recommended that you implement the diff --git a/gtk/a11y/gtkatspiutils.c b/gtk/a11y/gtkatspiutils.c index fad5ee10fd..7ec3193b9b 100644 --- a/gtk/a11y/gtkatspiutils.c +++ b/gtk/a11y/gtkatspiutils.c @@ -167,7 +167,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role) return ATSPI_ROLE_OPTION_PANE; case GTK_ACCESSIBLE_ROLE_PRESENTATION: - return ATSPI_ROLE_DOCUMENT_PRESENTATION; + return ATSPI_ROLE_SECTION; case GTK_ACCESSIBLE_ROLE_PROGRESS_BAR: return ATSPI_ROLE_PROGRESS_BAR; diff --git a/gtk/gtktreeexpander.c b/gtk/gtktreeexpander.c index 9ff4e6ac35..2a68df898d 100644 --- a/gtk/gtktreeexpander.c +++ b/gtk/gtktreeexpander.c @@ -158,7 +158,11 @@ gtk_tree_expander_update_for_list_row (GtkTreeExpander *self) { GtkGesture *gesture; - self->expander = gtk_builtin_icon_new ("expander"); + self->expander = + g_object_new (GTK_TYPE_BUILTIN_ICON, + "css-name", "expander", + "accessible-role", GTK_ACCESSIBLE_ROLE_BUTTON, + NULL); gesture = gtk_gesture_click_new (); gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), @@ -179,10 +183,22 @@ gtk_tree_expander_update_for_list_row (GtkTreeExpander *self) GTK_WIDGET (self), self->child); } + if (gtk_tree_list_row_get_expanded (self->list_row)) - gtk_widget_set_state_flags (self->expander, GTK_STATE_FLAG_CHECKED, FALSE); + { + gtk_widget_set_state_flags (self->expander, GTK_STATE_FLAG_CHECKED, FALSE); + gtk_accessible_update_state (GTK_ACCESSIBLE (self->expander), + GTK_ACCESSIBLE_STATE_EXPANDED, TRUE, + -1); + } else - gtk_widget_unset_state_flags (self->expander, GTK_STATE_FLAG_CHECKED); + { + gtk_widget_unset_state_flags (self->expander, GTK_STATE_FLAG_CHECKED); + gtk_accessible_update_state (GTK_ACCESSIBLE (self->expander), + GTK_ACCESSIBLE_STATE_EXPANDED, FALSE, + -1); + } + child = gtk_widget_get_prev_sibling (self->expander); } else @@ -201,14 +217,13 @@ gtk_tree_expander_update_for_list_row (GtkTreeExpander *self) child = gtk_widget_get_prev_sibling (child); else { - GtkWidget *indent = gtk_builtin_icon_new ("indent"); + GtkWidget *indent = + g_object_new (GTK_TYPE_BUILTIN_ICON, + "css-name", "indent", + "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION, + NULL); gtk_widget_insert_after (indent, GTK_WIDGET (self), NULL); - - /* The indent icon is not visible in the accessibility tree */ - gtk_accessible_update_state (GTK_ACCESSIBLE (indent), - GTK_ACCESSIBLE_STATE_HIDDEN, TRUE, - -1); } } @@ -231,9 +246,19 @@ gtk_tree_expander_list_row_notify_cb (GtkTreeListRow *list_row, if (self->expander) { if (gtk_tree_list_row_get_expanded (list_row)) - gtk_widget_set_state_flags (self->expander, GTK_STATE_FLAG_CHECKED, FALSE); + { + gtk_widget_set_state_flags (self->expander, GTK_STATE_FLAG_CHECKED, FALSE); + gtk_accessible_update_state (GTK_ACCESSIBLE (self->expander), + GTK_ACCESSIBLE_STATE_EXPANDED, TRUE, + -1); + } else - gtk_widget_unset_state_flags (self->expander, GTK_STATE_FLAG_CHECKED); + { + gtk_widget_unset_state_flags (self->expander, GTK_STATE_FLAG_CHECKED); + gtk_accessible_update_state (GTK_ACCESSIBLE (self->expander), + GTK_ACCESSIBLE_STATE_EXPANDED, FALSE, + -1); + } } } else if (pspec->name == g_intern_static_string ("item"))