From 1bdc8b90618b059534d447912c09c11f6cf961ab Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 10 Nov 2020 11:02:35 +0000 Subject: [PATCH] a11y: Proxy GtkWidget:accessible-role The accessible-role property in GtkWidget has three possible targets: - the :accessible-role of a GtkATContext, if realized - the accessible_role field of GtkWidgetPrivate - the accessible_role field of GtkWidgetClassPrivate When we set the accessible role of a widget using the GObject property mechanism, we want to either set the GtkWidgetPrivate.accessible_role field, if there's no ATContext *or* if the ATContext is not realized. Conversely, when we get the accessible-role property we want to have a series of fallbacks in place: - if GtkAccessible.get_at_context() returns an ATContext, and that ATContext is realized, return the :accessible-role of the context - if GtkWidgetPrivate.accessible_role is not WIDGET, return the stored accessible role - return GtkWidgetClassPrivate.accessible_role This should help catch the case of getting the accessible role of widgets that override GtkAccessible.get_at_context(), like GtkModelButton. See: #3342 --- gtk/gtkwidget.c | 71 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 023f0ceb3a..f3670fa96c 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -640,6 +640,9 @@ static void gtk_widget_buildable_custom_finished (GtkBuildable static void gtk_widget_buildable_parser_finished (GtkBuildable *buildable, GtkBuilder *builder); +static void gtk_widget_set_accessible_role (GtkWidget *self, + GtkAccessibleRole role); +static GtkAccessibleRole gtk_widget_get_accessible_role (GtkWidget *self); static GtkSizeRequestMode gtk_widget_real_get_request_mode (GtkWidget *widget); @@ -1731,21 +1734,7 @@ gtk_widget_set_property (GObject *object, gtk_widget_set_layout_manager (widget, g_value_dup_object (value)); break; case PROP_ACCESSIBLE_ROLE: - if (priv->at_context == NULL || !gtk_at_context_is_realized (priv->at_context)) - { - priv->accessible_role = g_value_get_enum (value); - if (priv->at_context) - g_object_set (priv->at_context, "accessible-role", priv->accessible_role, NULL); - g_object_notify_by_pspec (object, pspec); - } - else - { - char *role_str = g_enum_to_string (GTK_TYPE_ACCESSIBLE_ROLE, priv->accessible_role); - g_critical ("Widget of type “%s” already has an accessible role of type “%s”", - G_OBJECT_TYPE_NAME (object), - role_str); - g_free (role_str); - } + gtk_widget_set_accessible_role (widget, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1878,14 +1867,7 @@ gtk_widget_get_property (GObject *object, g_value_set_object (value, gtk_widget_get_layout_manager (widget)); break; case PROP_ACCESSIBLE_ROLE: - { - GtkAccessibleRole role = priv->accessible_role; - - if (priv->accessible_role == GTK_ACCESSIBLE_ROLE_WIDGET) - role = gtk_widget_class_get_accessible_role (GTK_WIDGET_GET_CLASS (widget)); - - g_value_set_enum (value, role); - } + g_value_set_enum (value, gtk_widget_get_accessible_role (widget)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -12564,6 +12546,49 @@ gtk_widget_update_orientation (GtkWidget *widget, -1); } +static void +gtk_widget_set_accessible_role (GtkWidget *self, + GtkAccessibleRole role) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + + if (priv->at_context == NULL || !gtk_at_context_is_realized (priv->at_context)) + { + priv->accessible_role = role; + + if (priv->at_context != NULL) + g_object_set (priv->at_context, "accessible-role", priv->accessible_role, NULL); + + g_object_notify (G_OBJECT (self), "accessible-role"); + } + else + { + char *role_str = g_enum_to_string (GTK_TYPE_ACCESSIBLE_ROLE, priv->accessible_role); + + g_critical ("Widget of type “%s” already has an accessible role of type “%s”", + G_OBJECT_TYPE_NAME (self), + role_str); + g_free (role_str); + } +} + +static GtkAccessibleRole +gtk_widget_get_accessible_role (GtkWidget *self) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self)); + + if (context == NULL || !gtk_at_context_is_realized (context)) + { + if (priv->accessible_role == GTK_ACCESSIBLE_ROLE_WIDGET) + return gtk_widget_class_get_accessible_role (GTK_WIDGET_GET_CLASS (self)); + + return priv->accessible_role; + } + + return gtk_at_context_get_accessible_role (context); +} + /** * gtk_widget_class_set_accessible_role: * @widget_class: a #GtkWidgetClass