From: Matthias Clasen Date: Sun, 18 Jun 2023 12:12:31 +0000 (-0400) Subject: a11y: Special-case nested buttons X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~130^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=743b27571da5d793bc97c69d9a66f54ecceadcf0;p=gtk4.git a11y: Special-case nested buttons Special-case nested buttons in our name computation, since it is hard to reconcile all the a11y attributes being on the wrapper, but the focus ending up on the button inside. This is a pragmatic approach that works. The only downside is that the wrapper and the button end up with the same name+description, but at least orca seems to only read the focus elements' ones. --- diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c index 922ca94668..2d6908cd7a 100644 --- a/gtk/gtkatcontext.c +++ b/gtk/gtkatcontext.c @@ -40,6 +40,13 @@ #include "gtktestatcontextprivate.h" #include "gtktypebuiltins.h" +#include "gtkbutton.h" +#include "gtktogglebutton.h" +#include "gtkmenubutton.h" +#include "gtkdropdown.h" +#include "gtkcolordialogbutton.h" +#include "gtkfontdialogbutton.h" + #if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WAYLAND) #include "a11y/gtkatspicontextprivate.h" #endif @@ -1176,6 +1183,47 @@ static GtkAccessibleRole name_forbidden[] = { GTK_ACCESSIBLE_ROLE_NONE, }; +static gboolean +is_nested_button (GtkATContext *self) +{ + GtkAccessible *accessible; + GtkWidget *widget, *parent; + + accessible = gtk_at_context_get_accessible (self); + + if (!GTK_IS_WIDGET (accessible)) + return FALSE; + + widget = GTK_WIDGET (accessible); + parent = gtk_widget_get_parent (widget); + + if ((GTK_IS_TOGGLE_BUTTON (widget) && GTK_IS_DROP_DOWN (parent)) || + (GTK_IS_TOGGLE_BUTTON (widget) && GTK_IS_MENU_BUTTON (parent)) || + (GTK_IS_BUTTON (widget) && GTK_IS_COLOR_DIALOG_BUTTON (parent)) || + (GTK_IS_BUTTON (widget) && GTK_IS_FONT_DIALOG_BUTTON (parent))) + return TRUE; + + return FALSE; +} + +static GtkATContext * +get_parent_context (GtkATContext *self) +{ + GtkAccessible *accessible, *parent; + + accessible = gtk_at_context_get_accessible (self); + parent = gtk_accessible_get_accessible_parent (accessible); + if (parent) + { + GtkATContext *context = gtk_accessible_get_at_context (parent); + g_object_unref (parent); + return context; + } + + return g_object_ref (self); +} + + /*< private > * gtk_at_context_get_name: * @self: a `GtkATContext` @@ -1189,6 +1237,8 @@ static GtkAccessibleRole name_forbidden[] = { char * gtk_at_context_get_name (GtkATContext *self) { + GtkATContext *parent = NULL; + g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL); for (unsigned int i = 0; i < G_N_ELEMENTS (name_forbidden); i++) @@ -1197,6 +1247,18 @@ gtk_at_context_get_name (GtkATContext *self) return g_strdup (""); } + /* We special case this here since it is a common pattern: + * We have a 'wrapper' object, like a GtkDropdown which + * contains a toggle button. The dropdown appears in the + * ui file and carries all the a11y attributes, but the + * focus ends up on the toggle button. + */ + if (is_nested_button (self)) + { + parent = get_parent_context (self); + self = parent; + } + GPtrArray *names = g_ptr_array_new (); gtk_at_context_get_name_accumulate (self, names, TRUE); @@ -1204,6 +1266,7 @@ gtk_at_context_get_name (GtkATContext *self) if (names->len == 0) { g_ptr_array_unref (names); + g_clear_object (&parent); return g_strdup (""); } @@ -1218,6 +1281,8 @@ gtk_at_context_get_name (GtkATContext *self) g_ptr_array_unref (names); + g_clear_object (&parent); + return g_string_free (res, FALSE); } @@ -1234,6 +1299,8 @@ gtk_at_context_get_name (GtkATContext *self) char * gtk_at_context_get_description (GtkATContext *self) { + GtkATContext *parent = NULL; + g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL); for (unsigned int i = 0; i < G_N_ELEMENTS (name_forbidden); i++) @@ -1242,6 +1309,18 @@ gtk_at_context_get_description (GtkATContext *self) return g_strdup (""); } + /* We special case this here since it is a common pattern: + * We have a 'wrapper' object, like a GtkDropdown which + * contains a toggle button. The dropdown appears in the + * ui file and carries all the a11y attributes, but the + * focus ends up on the toggle button. + */ + if (is_nested_button (self)) + { + parent = get_parent_context (self); + self = parent; + } + GPtrArray *names = g_ptr_array_new (); gtk_at_context_get_description_accumulate (self, names, TRUE); @@ -1249,6 +1328,7 @@ gtk_at_context_get_description (GtkATContext *self) if (names->len == 0) { g_ptr_array_unref (names); + g_clear_object (&parent); return g_strdup (""); } @@ -1263,6 +1343,7 @@ gtk_at_context_get_description (GtkATContext *self) g_ptr_array_unref (names); + g_clear_object (&parent); return g_string_free (res, FALSE); }