From 428ec295981492f16da9efac52f126305735071c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 10 Nov 2020 17:18:55 +0000 Subject: a11y: Unrealize ATContext on dispose() By unrealizing the context we avoid additional work during the dispose phase, in case widget code updates the accessible state. We use GtkAccessible's API, to ensure we unrealize the right ATContext, instead of the one we store inside GtkWidgetPrivate. We drop the ATContext instance inside GtkWidget during finalization, to mop up eventual vivifications there. --- gtk/gtkwidget.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index c29cc88ec0..48a394a766 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -7028,6 +7028,7 @@ gtk_widget_dispose (GObject *object) GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); GSList *sizegroups; GtkActionMuxer *muxer; + GtkATContext *at_context; muxer = g_object_get_qdata (G_OBJECT (widget), quark_action_muxer); if (muxer != NULL) @@ -7050,8 +7051,6 @@ gtk_widget_dispose (GObject *object) gtk_layout_manager_set_widget (priv->layout_manager, NULL); g_clear_object (&priv->layout_manager); - g_clear_object (&priv->at_context); - priv->visible = FALSE; if (_gtk_widget_get_realized (widget)) gtk_widget_unrealize (widget); @@ -7076,6 +7075,10 @@ gtk_widget_dispose (GObject *object) gtk_size_group_remove_widget (size_group, widget); } + at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget)); + if (at_context != NULL) + gtk_at_context_unrealize (at_context); + g_object_set_qdata (object, quark_action_muxer, NULL); G_OBJECT_CLASS (gtk_widget_parent_class)->dispose (object); @@ -7237,6 +7240,7 @@ gtk_widget_finalize (GObject *object) g_object_unref (priv->cssnode); g_clear_object (&priv->context); + g_clear_object (&priv->at_context); _gtk_size_request_cache_free (&priv->requests); -- cgit v1.2.1 From 3b2cd972d5ae60f93b5aa1a97bd0c9dab7dd60cb Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:43:44 +0000 Subject: a11y: Implement missing atspi.Component getters Some of them are entirely innocuous, and we can easily provide values that match what GTK3 provides. --- gtk/a11y/gtkatspicomponent.c | 19 ++++++++++++++++--- gtk/a11y/gtkatspiprivate.h | 12 ++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/gtk/a11y/gtkatspicomponent.c b/gtk/a11y/gtkatspicomponent.c index 2ab1ffc81c..7da968d1d1 100644 --- a/gtk/a11y/gtkatspicomponent.c +++ b/gtk/a11y/gtkatspicomponent.c @@ -26,7 +26,9 @@ #include "gtkatspiprivate.h" #include "gtkatspiutilsprivate.h" #include "gtkaccessibleprivate.h" +#include "gtkpopover.h" #include "gtkwidget.h" +#include "gtkwindow.h" #include "a11y/atspi/atspi-component.h" @@ -194,11 +196,20 @@ component_handle_method (GDBusConnection *connection, } else if (g_strcmp0 (method_name, "GetLayer") == 0) { - g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); + AtspiComponentLayer layer; + + if (GTK_IS_WINDOW (widget)) + layer = ATSPI_COMPONENT_LAYER_WINDOW; + else if (GTK_IS_POPOVER (widget)) + layer = ATSPI_COMPONENT_LAYER_POPUP; + else + layer = ATSPI_COMPONENT_LAYER_WIDGET; + + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", layer)); } else if (g_strcmp0 (method_name, "GetMDIZOrder") == 0) { - g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(n)", 0)); } else if (g_strcmp0 (method_name, "GrabFocus") == 0) { @@ -206,7 +217,9 @@ component_handle_method (GDBusConnection *connection, } else if (g_strcmp0 (method_name, "GetAlpha") == 0) { - g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); + double opacity = gtk_widget_get_opacity (widget); + + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(d)", opacity)); } else if (g_strcmp0 (method_name, "SetExtents") == 0) { diff --git a/gtk/a11y/gtkatspiprivate.h b/gtk/a11y/gtkatspiprivate.h index 9d3d316354..036a41ef27 100644 --- a/gtk/a11y/gtkatspiprivate.h +++ b/gtk/a11y/gtkatspiprivate.h @@ -252,4 +252,16 @@ typedef enum { ATSPI_COORD_TYPE_PARENT, } AtspiCoordType; +typedef enum { + ATSPI_COMPONENT_LAYER_INVALID, + ATSPI_COMPONENT_LAYER_BACKGROUND, + ATSPI_COMPONENT_LAYER_CANVAS, + ATSPI_COMPONENT_LAYER_WIDGET, + ATSPI_COMPONENT_LAYER_MDI, + ATSPI_COMPONENT_LAYER_POPUP, + ATSPI_COMPONENT_LAYER_OVERLAY, + ATSPI_COMPONENT_LAYER_WINDOW +} AtspiComponentLayer; + + G_END_DECLS -- cgit v1.2.1 From 65d29e00c7024aa21a7fe15d7fcda6fc7242af8c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:45:32 +0000 Subject: a11y: Realize parent ATContext for the stack page Just like for popovers, the stack page is not directly connected on the widget's DOM, so we need to realize the parent ATContext ourselves. --- gtk/a11y/gtkatspicontext.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gtk/a11y/gtkatspicontext.c b/gtk/a11y/gtkatspicontext.c index 98bde0a0e7..8a83ed838d 100644 --- a/gtk/a11y/gtkatspicontext.c +++ b/gtk/a11y/gtkatspicontext.c @@ -411,7 +411,11 @@ get_parent_context_ref (GtkAccessible *accessible) gtk_accessible_get_at_context (GTK_ACCESSIBLE (page)); if (parent_context != NULL) - res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context)); + { + gtk_at_context_realize (parent_context); + + res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context)); + } } else { -- cgit v1.2.1 From 95ee5ff4242f1808edb37f555f402722c0aa98ef Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:49:14 +0000 Subject: a11y: Add more ARIA/AT-SPI role translations --- gtk/a11y/gtkatspiutils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gtk/a11y/gtkatspiutils.c b/gtk/a11y/gtkatspiutils.c index 7ec3193b9b..a448ea67b4 100644 --- a/gtk/a11y/gtkatspiutils.c +++ b/gtk/a11y/gtkatspiutils.c @@ -80,7 +80,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role) break; case GTK_ACCESSIBLE_ROLE_FORM: - break; + return ATSPI_ROLE_FORM; case GTK_ACCESSIBLE_ROLE_GENERIC: break; @@ -92,10 +92,10 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role) return ATSPI_ROLE_TABLE_CELL; case GTK_ACCESSIBLE_ROLE_GROUP: - break; + return ATSPI_ROLE_PANEL; case GTK_ACCESSIBLE_ROLE_HEADING: - break; + return ATSPI_ROLE_HEADING; case GTK_ACCESSIBLE_ROLE_IMG: return ATSPI_ROLE_IMAGE; @@ -110,7 +110,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role) break; case GTK_ACCESSIBLE_ROLE_LEGEND: - break; + return ATSPI_ROLE_LABEL; case GTK_ACCESSIBLE_ROLE_LINK: return ATSPI_ROLE_LINK; @@ -134,7 +134,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role) return ATSPI_ROLE_MARQUEE; case GTK_ACCESSIBLE_ROLE_MATH: - return ATSPI_ROLE_MATH;; + return ATSPI_ROLE_MATH; case GTK_ACCESSIBLE_ROLE_METER: return ATSPI_ROLE_LEVEL_BAR; -- cgit v1.2.1 From 033791b37469a59340b21a6c69cd37f2b7ce886b Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:49:38 +0000 Subject: a11y: Translate ARIA windows to AT-SPI frames For backward compatibility with GTK3. --- gtk/a11y/gtkatspiutils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtk/a11y/gtkatspiutils.c b/gtk/a11y/gtkatspiutils.c index a448ea67b4..87b1887fe8 100644 --- a/gtk/a11y/gtkatspiutils.c +++ b/gtk/a11y/gtkatspiutils.c @@ -269,7 +269,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role) return ATSPI_ROLE_FILLER; case GTK_ACCESSIBLE_ROLE_WINDOW: - return ATSPI_ROLE_WINDOW; + return ATSPI_ROLE_FRAME; default: break; @@ -294,6 +294,7 @@ gtk_atspi_role_for_context (GtkATContext *context) GtkAccessible *accessible = gtk_at_context_get_accessible (context); GtkAccessibleRole role = gtk_at_context_get_accessible_role (context); + /* ARIA does not have a "password entry" role, so we need to fudge it here */ if (GTK_IS_PASSWORD_ENTRY (accessible)) return ATSPI_ROLE_PASSWORD_TEXT; -- cgit v1.2.1 From 04c4d293a727ebc79a8baebe2463782ce1c6a69a Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:50:42 +0000 Subject: a11y: Skip unlabelled structural roles If a structural role is left unlabelled, just leave it unnamed. --- gtk/gtkatcontext.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c index 661ac848b1..74f368d5e7 100644 --- a/gtk/gtkatcontext.c +++ b/gtk/gtkatcontext.c @@ -862,6 +862,27 @@ gtk_at_context_get_accessible_relation (GtkATContext *self, return gtk_accessible_attribute_set_get_value (self->relations, relation); } +static gboolean +is_structural_role (GtkAccessibleRole role) +{ + /* Keep the switch small while avoiding the compiler warning for + * unhandled enumeration values + */ + switch ((int) role) + { + case GTK_ACCESSIBLE_ROLE_FORM: + case GTK_ACCESSIBLE_ROLE_GROUP: + case GTK_ACCESSIBLE_ROLE_GENERIC: + case GTK_ACCESSIBLE_ROLE_REGION: + return TRUE; + + default: + break; + } + + return FALSE; +} + /* See the WAI-ARIA § 4.3, "Accessible Name and Description Computation" */ static void gtk_at_context_get_name_accumulate (GtkATContext *self, @@ -937,7 +958,8 @@ gtk_at_context_get_name_accumulate (GtkATContext *self, if (names->len != 0) return; - if (self->accessible) + /* Ignore structural elements, namely: generic containers */ + if (self->accessible != NULL && !is_structural_role (role)) g_ptr_array_add (names, (char *)G_OBJECT_TYPE_NAME (self->accessible)); } -- cgit v1.2.1 From 27b9b2e76c9b938927a5bcb9200e119c773fefc3 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:51:56 +0000 Subject: a11y: Use the window title as its label --- gtk/gtkwindow.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 6e8f289d0b..68889591e7 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -1965,6 +1965,10 @@ gtk_window_set_title (GtkWindow *window, if (_gtk_widget_get_realized (GTK_WIDGET (window))) gdk_toplevel_set_title (GDK_TOPLEVEL (priv->surface), new_title != NULL ? new_title : ""); + gtk_accessible_update_property (GTK_ACCESSIBLE (window), + GTK_ACCESSIBLE_PROPERTY_LABEL, priv->title, + -1); + g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_TITLE]); } -- cgit v1.2.1 From 40c0826921d9d59fe4a165fa1717e23cc9ceedb7 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 17:54:57 +0000 Subject: a11y: Mark more containers as structural elements Widgets that just provide grouping and layout to other widgets should not be relevant to the accessible tree. --- gtk/gtkaspectframe.c | 1 + gtk/gtkbox.c | 1 + gtk/gtkcenterbox.c | 1 + gtk/gtkgrid.c | 2 +- gtk/gtkheaderbar.c | 1 + gtk/gtkscrolledwindow.c | 1 + gtk/gtkviewport.c | 1 + gtk/gtkwindowcontrols.c | 1 + gtk/gtkwindowhandle.c | 1 + 9 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gtk/gtkaspectframe.c b/gtk/gtkaspectframe.c index ad6049ffe9..916f307daf 100644 --- a/gtk/gtkaspectframe.c +++ b/gtk/gtkaspectframe.c @@ -176,6 +176,7 @@ gtk_aspect_frame_class_init (GtkAspectFrameClass *class) GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("aspectframe")); + gtk_widget_class_set_accessible_role (GTK_WIDGET_CLASS (class), GTK_ACCESSIBLE_ROLE_GROUP); } static void diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c index b23d523ac2..39aafdecd8 100644 --- a/gtk/gtkbox.c +++ b/gtk/gtkbox.c @@ -278,6 +278,7 @@ gtk_box_class_init (GtkBoxClass *class) gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("box")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void gtk_box_init (GtkBox *box) diff --git a/gtk/gtkcenterbox.c b/gtk/gtkcenterbox.c index 76f07ad6ba..097d135017 100644 --- a/gtk/gtkcenterbox.c +++ b/gtk/gtkcenterbox.c @@ -210,6 +210,7 @@ gtk_center_box_class_init (GtkCenterBoxClass *klass) gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CENTER_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("box")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c index 3a5b6a7a95..4c21f29806 100644 --- a/gtk/gtkgrid.c +++ b/gtk/gtkgrid.c @@ -395,8 +395,8 @@ gtk_grid_class_init (GtkGridClass *class) g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); gtk_widget_class_set_css_name (widget_class, I_("grid")); - gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_GRID_LAYOUT); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static GtkBuildableIface *parent_buildable_iface; diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c index 8147a86496..745d5ce672 100644 --- a/gtk/gtkheaderbar.c +++ b/gtk/gtkheaderbar.c @@ -600,6 +600,7 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class) gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("headerbar")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index afa250c846..52a8ac77d4 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -868,6 +868,7 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) add_tab_bindings (widget_class, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD); gtk_widget_class_set_css_name (widget_class, I_("scrolledwindow")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static gboolean diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c index 43df2cddae..8fdef6123d 100644 --- a/gtk/gtkviewport.c +++ b/gtk/gtkviewport.c @@ -382,6 +382,7 @@ gtk_viewport_class_init (GtkViewportClass *class) GTK_PARAM_READWRITE)); gtk_widget_class_set_css_name (widget_class, I_("viewport")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void diff --git a/gtk/gtkwindowcontrols.c b/gtk/gtkwindowcontrols.c index d2b3667555..7278dfafff 100644 --- a/gtk/gtkwindowcontrols.c +++ b/gtk/gtkwindowcontrols.c @@ -538,6 +538,7 @@ gtk_window_controls_class_init (GtkWindowControlsClass *klass) gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("windowcontrols")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void diff --git a/gtk/gtkwindowhandle.c b/gtk/gtkwindowhandle.c index 18919becac..fca0c3440d 100644 --- a/gtk/gtkwindowhandle.c +++ b/gtk/gtkwindowhandle.c @@ -550,6 +550,7 @@ gtk_window_handle_class_init (GtkWindowHandleClass *klass) gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("windowhandle")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void -- cgit v1.2.1 From 73b14a3c3a980be4a8860532914a16fb61cc410b Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 18:08:16 +0000 Subject: a11y: Do not leak the ATContext in GtkStackPage GtkStackPage is not a widget, so it must release the reference on the ATContext it owns. --- gtk/gtkstack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c index bb6ecfeb12..3d70475ff9 100644 --- a/gtk/gtkstack.c +++ b/gtk/gtkstack.c @@ -274,6 +274,8 @@ gtk_stack_page_finalize (GObject *object) g_object_remove_weak_pointer (G_OBJECT (page->last_focus), (gpointer *)&page->last_focus); + g_clear_object (&page->at_context); + G_OBJECT_CLASS (gtk_stack_page_parent_class)->finalize (object); } -- cgit v1.2.1 From 877a7f98caacbfbbd253f43cb05e5a8571cbb707 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 18:09:43 +0000 Subject: a11y: Protect should_present() from empty contexts If the GtkAccessible implementation returns a NULL context, we should not be calling methods on it. --- gtk/gtkaccessible.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c index 13c4cb35ed..e9f8d7d663 100644 --- a/gtk/gtkaccessible.c +++ b/gtk/gtkaccessible.c @@ -678,9 +678,7 @@ gtk_accessible_platform_changed (GtkAccessible *self, /* propagate changes up from ignored widgets */ if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE) - { - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (gtk_widget_get_parent (GTK_WIDGET (self)))); - } + context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (gtk_widget_get_parent (GTK_WIDGET (self)))); if (context == NULL) return; @@ -765,6 +763,9 @@ gtk_accessible_should_present (GtkAccessible *self) return FALSE; context = gtk_accessible_get_at_context (self); + if (context == NULL) + return FALSE; + if (gtk_at_context_has_accessible_state (context, GTK_ACCESSIBLE_STATE_HIDDEN)) { GtkAccessibleValue *value; -- cgit v1.2.1 From 526f1e315b7a06ec48f6e258c2cad529724186e2 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 18:11:10 +0000 Subject: a11y: Use GROUP role for GtkNotebook A notebook is a grouping of a tab list, tabs, and tab pages. --- gtk/gtknotebook.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 6f96faeee1..945a13da6a 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -1369,6 +1369,7 @@ gtk_notebook_class_init (GtkNotebookClass *class) gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); gtk_widget_class_set_css_name (widget_class, I_("notebook")); + gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP); } static void -- cgit v1.2.1 From 228538207470d41f0c6be6bd989b56307da4a749 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 18:15:18 +0000 Subject: a11y: Create AtSpiRoot on realization There's no need to do a lot of work on construction, if we're delaying all remote work after the GtkATContext is realized. The GtkAtSpiContext should also keep a reference on the root, and drop it at unrealize time. --- gtk/a11y/gtkatspicontext.c | 50 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/gtk/a11y/gtkatspicontext.c b/gtk/a11y/gtkatspicontext.c index 8a83ed838d..4dad9863dd 100644 --- a/gtk/a11y/gtkatspicontext.c +++ b/gtk/a11y/gtkatspicontext.c @@ -46,9 +46,10 @@ #include "gtkeditable.h" #include "gtkentryprivate.h" #include "gtkroot.h" +#include "gtkstack.h" #include "gtktextview.h" +#include "gtktypebuiltins.h" #include "gtkwindow.h" -#include "gtkstack.h" #include @@ -1403,6 +1404,8 @@ gtk_at_spi_context_finalize (GObject *gobject) gtk_at_spi_context_unregister_object (self); + g_clear_object (&self->root); + g_free (self->bus_address); g_free (self->context_path); @@ -1451,8 +1454,8 @@ static void gtk_at_spi_context_constructed (GObject *gobject) { GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (gobject); - GdkDisplay *display = gtk_at_context_get_display (GTK_AT_CONTEXT (self)); + /* Make sure that we were properly constructed */ g_assert (self->bus_address); /* We use the application's object path to build the path of each @@ -1494,10 +1497,19 @@ gtk_at_spi_context_constructed (GObject *gobject) g_free (base_path); g_free (uuid); + G_OBJECT_CLASS (gtk_at_spi_context_parent_class)->constructed (gobject); +} + +static void +gtk_at_spi_context_realize (GtkATContext *context) +{ + GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context); + GdkDisplay *display = gtk_at_context_get_display (context); + /* Every GTK application has a single root AT-SPI object, which * handles all the global state, including the cache of accessible * objects. We use the GdkDisplay to store it, so it's guaranteed - * to be unique per-display connection + * to be a unique per-display connection */ self->root = g_object_get_data (G_OBJECT (display), "-gtk-atspi-root"); @@ -1506,26 +1518,32 @@ gtk_at_spi_context_constructed (GObject *gobject) { self->root = gtk_at_spi_root_new (self->bus_address); g_object_set_data_full (G_OBJECT (display), "-gtk-atspi-root", - self->root, + g_object_ref (self->root), g_object_unref); } - - G_OBJECT_CLASS (gtk_at_spi_context_parent_class)->constructed (gobject); -} - -static void -gtk_at_spi_context_realize (GtkATContext *context) -{ - GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context); + else + { + g_object_ref (self->root); + } self->connection = gtk_at_spi_root_get_connection (self->root); if (self->connection == NULL) return; GtkAccessible *accessible = gtk_at_context_get_accessible (context); - GTK_NOTE (A11Y, g_message ("Realizing ATSPI context at '%s' for accessible '%s'", - self->context_path, - G_OBJECT_TYPE_NAME (accessible))); + +#ifdef G_ENABLE_DEBUG + if (GTK_DEBUG_CHECK (A11Y)) + { + GtkAccessibleRole role = gtk_at_context_get_accessible_role (context); + char *role_name = g_enum_to_string (GTK_TYPE_ACCESSIBLE_ROLE, role); + g_message ("Realizing ATSPI context “%s” for accessible “%s”, with role: “%s”", + self->context_path, + G_OBJECT_TYPE_NAME (accessible), + role_name); + g_free (role_name); + } +#endif gtk_atspi_connect_text_signals (accessible, (GtkAtspiTextChangedCallback *)emit_text_changed, @@ -1555,6 +1573,8 @@ gtk_at_spi_context_unrealize (GtkATContext *context) gtk_atspi_disconnect_text_signals (accessible); gtk_atspi_disconnect_selection_signals (accessible); gtk_at_spi_context_unregister_object (self); + + g_clear_object (&self->root); } static void -- cgit v1.2.1 From 292576f3129a1bd73d3b5b4ad0e41d70df1c805e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 19:37:26 +0000 Subject: a11y: Defer to the GtkAccessible's implementation Since GtkATContexts are now lazily realized, we need to go through the GtkAccessible's implementation to access the :accessible-role property, in case there are fallbacks. --- gtk/gtkaccessible.c | 10 +++++++--- gtk/gtktestatcontext.c | 8 +------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c index e9f8d7d663..991bc02756 100644 --- a/gtk/gtkaccessible.c +++ b/gtk/gtkaccessible.c @@ -104,13 +104,17 @@ gtk_accessible_get_at_context (GtkAccessible *self) GtkAccessibleRole gtk_accessible_get_accessible_role (GtkAccessible *self) { + GtkAccessibleRole role; + g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), GTK_ACCESSIBLE_ROLE_NONE); GtkATContext *context = gtk_accessible_get_at_context (self); - if (context == NULL) - return GTK_ACCESSIBLE_ROLE_NONE; + if (context != NULL && gtk_at_context_is_realized (context)) + return gtk_at_context_get_accessible_role (context); + + g_object_get (G_OBJECT (self), "accessible-role", &role, NULL); - return gtk_at_context_get_accessible_role (context); + return role; } /** diff --git a/gtk/gtktestatcontext.c b/gtk/gtktestatcontext.c index c8bd222d1a..27ad90da67 100644 --- a/gtk/gtktestatcontext.c +++ b/gtk/gtktestatcontext.c @@ -118,15 +118,9 @@ gboolean gtk_test_accessible_has_role (GtkAccessible *accessible, GtkAccessibleRole role) { - GtkATContext *context; - g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); - context = gtk_accessible_get_at_context (accessible); - if (context == NULL) - return FALSE; - - return gtk_at_context_get_accessible_role (context) == role; + return gtk_accessible_get_accessible_role (accessible) == role; } gboolean -- cgit v1.2.1 From 9052f6dafe15082aa05e25c0267b30f668488e9f Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 18:17:41 +0000 Subject: a11y: Rework ownership and lifetime of GtkATContext Now that GtkATContext is explicitly realized and unrealized, we should always create an instance at widget initialization time, and drop it during the widget finalization. This should make it easier to set up the initial accessible state of a widget during the instance initialization, as well as reduce the chances of accidental creation of GtkATContext instances during the destruction sequence. --- gtk/gtkatcontext.c | 64 +++++++++++++++++++++++++--- gtk/gtkatcontextprivate.h | 4 ++ gtk/gtkwidget.c | 105 +++++++++++++++++++++++++++------------------- 3 files changed, 123 insertions(+), 50 deletions(-) diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c index 74f368d5e7..8c49c27118 100644 --- a/gtk/gtkatcontext.c +++ b/gtk/gtkatcontext.c @@ -111,7 +111,7 @@ gtk_at_context_set_property (GObject *gobject, break; case PROP_DISPLAY: - self->display = g_value_get_object (value); + gtk_at_context_set_display (self, g_value_get_object (value)); break; default: @@ -245,8 +245,8 @@ gtk_at_context_class_init (GtkATContextClass *klass) "The display connection", GDK_TYPE_DISPLAY, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); /** * GtkATContext::state-change: @@ -385,15 +385,15 @@ gtk_at_context_init (GtkATContext *self) self->accessible_role = GTK_ACCESSIBLE_ROLE_NONE; self->properties = - gtk_accessible_attribute_set_new (N_PROPERTIES, + gtk_accessible_attribute_set_new (G_N_ELEMENTS (property_attrs), property_attrs, (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_property); self->relations = - gtk_accessible_attribute_set_new (N_RELATIONS, + gtk_accessible_attribute_set_new (G_N_ELEMENTS (relation_attrs), relation_attrs, (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_relation); self->states = - gtk_accessible_attribute_set_new (N_STATES, + gtk_accessible_attribute_set_new (G_N_ELEMENTS (state_attrs), state_attrs, (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_state); } @@ -414,6 +414,30 @@ gtk_at_context_get_accessible (GtkATContext *self) return self->accessible; } +/*< private > + * gtk_at_context_set_accessible_role: + * @self: a #GtkATContext + * @role: the accessible role for the context + * + * Sets the accessible role for the given #GtkATContext. + * + * This function can only be called if the #GtkATContext is unrealized. + */ +void +gtk_at_context_set_accessible_role (GtkATContext *self, + GtkAccessibleRole role) +{ + g_return_if_fail (GTK_IS_AT_CONTEXT (self)); + g_return_if_fail (!self->realized); + + if (self->accessible_role == role) + return; + + self->accessible_role = role; + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACCESSIBLE_ROLE]); +} + /** * gtk_at_context_get_accessible_role: * @self: a #GtkATContext @@ -430,6 +454,34 @@ gtk_at_context_get_accessible_role (GtkATContext *self) return self->accessible_role; } +/*< private > + * gtk_at_context_set_display: + * @self: a #GtkATContext + * @display: a #GdkDisplay + * + * Sets the #GdkDisplay used by the #GtkATContext. + * + * This function can only be called if the #GtkATContext is + * not realized. + */ +void +gtk_at_context_set_display (GtkATContext *self, + GdkDisplay *display) +{ + g_return_if_fail (GTK_IS_AT_CONTEXT (self)); + g_return_if_fail (display == NULL || GDK_IS_DISPLAY (display)); + + if (self->display == display) + return; + + if (self->realized) + return; + + self->display = display; + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DISPLAY]); +} + /*< private > * gtk_at_context_get_display: * @self: a #GtkATContext diff --git a/gtk/gtkatcontextprivate.h b/gtk/gtkatcontextprivate.h index f1b62f8cb8..d9678cbea5 100644 --- a/gtk/gtkatcontextprivate.h +++ b/gtk/gtkatcontextprivate.h @@ -150,7 +150,11 @@ GtkATContext * gtk_at_context_clone (GtkATContext GtkAccessible *accessible, GdkDisplay *display); +void gtk_at_context_set_display (GtkATContext *self, + GdkDisplay *display); GdkDisplay * gtk_at_context_get_display (GtkATContext *self); +void gtk_at_context_set_accessible_role (GtkATContext *self, + GtkAccessibleRole role); void gtk_at_context_realize (GtkATContext *self); void gtk_at_context_unrealize (GtkATContext *self); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 48a394a766..7c848040e3 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -771,8 +771,6 @@ gtk_widget_base_class_init (gpointer g_class) g_object_unref (shortcut); } } - - priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET; } static void @@ -1624,6 +1622,7 @@ gtk_widget_class_init (GtkWidgetClass *klass) _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECTv); gtk_widget_class_set_css_name (klass, I_("widget")); + gtk_widget_class_set_accessible_role (klass, GTK_ACCESSIBLE_ROLE_WIDGET); } static void @@ -2300,6 +2299,34 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class) gtk_event_controller_set_name (controller, "gtk-widget-class-shortcuts"); gtk_widget_add_controller (widget, controller); } + + priv->at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget)); +} + +static void +gtk_widget_realize_at_context (GtkWidget *self) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + GtkAccessibleRole role = priv->accessible_role; + + if (gtk_at_context_is_realized (priv->at_context)) + return; + + /* Realize the root ATContext first */ + if (!GTK_IS_ROOT (self)) + gtk_widget_realize_at_context (GTK_WIDGET (priv->root)); + + /* Reset the accessible role to its current value */ + if (role == GTK_ACCESSIBLE_ROLE_WIDGET) + { + GtkWidgetClassPrivate *class_priv = GTK_WIDGET_GET_CLASS (self)->priv; + + role = class_priv->accessible_role; + } + + gtk_at_context_set_accessible_role (priv->at_context, role); + gtk_at_context_set_display (priv->at_context, gtk_root_get_display (priv->root)); + gtk_at_context_realize (priv->at_context); } void @@ -2330,15 +2357,7 @@ gtk_widget_root (GtkWidget *widget) if (priv->layout_manager) gtk_layout_manager_set_root (priv->layout_manager, priv->root); - if (priv->at_context != NULL) - { - GtkATContext *root_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (priv->root)); - - if (root_context) - gtk_at_context_realize (root_context); - - gtk_at_context_realize (priv->at_context); - } + gtk_widget_realize_at_context (widget); GTK_WIDGET_GET_CLASS (widget)->root (widget); @@ -2364,8 +2383,8 @@ gtk_widget_unroot (GtkWidget *widget) GTK_WIDGET_GET_CLASS (widget)->unroot (widget); - if (priv->at_context) - gtk_at_context_unrealize (priv->at_context); + gtk_at_context_set_display (priv->at_context, gdk_display_get_default ()); + gtk_at_context_unrealize (priv->at_context); if (priv->context) gtk_style_context_set_display (priv->context, gdk_display_get_default ()); @@ -8109,33 +8128,36 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible) { GtkWidget *self = GTK_WIDGET (accessible); GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self); + GtkWidgetClassPrivate *class_priv = widget_class->priv; + GtkAccessibleRole role; if (priv->in_destruction) - return NULL; - - if (priv->at_context == NULL) { - GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self); - GtkWidgetClassPrivate *class_priv = widget_class->priv; - GdkDisplay *display = _gtk_widget_get_display (self); - GtkAccessibleRole role; + GTK_NOTE (A11Y, g_message ("ATContext for widget “%s” [%p] accessed during destruction", + G_OBJECT_TYPE_NAME (self), + self)); + return NULL; + } - /* Widgets have two options to set the accessible role: either they - * define it in their class_init() function, and the role applies to - * all instances; or an instance is created with the :accessible-role - * property (from GtkAccessible) set to anything other than the default - * GTK_ACCESSIBLE_ROLE_WIDGET value. - * - * In either case, the accessible role cannot be set post-construction. - */ - if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET) - role = priv->accessible_role; - else - role = class_priv->accessible_role; + if (priv->at_context != NULL) + return priv->at_context; - priv->accessible_role = role; - priv->at_context = gtk_at_context_create (role, accessible, display); - } + /* Widgets have two options to set the accessible role: either they + * define it in their class_init() function, and the role applies to + * all instances; or an instance is created with the :accessible-role + * property (from GtkAccessible) set to anything other than the default + * GTK_ACCESSIBLE_ROLE_WIDGET value. + * + * In either case, the accessible role cannot be set post-construction. + */ + if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET) + role = priv->accessible_role; + else + role = class_priv->accessible_role; + + priv->accessible_role = role; + priv->at_context = gtk_at_context_create (role, accessible, gdk_display_get_default ()); return priv->at_context; } @@ -12565,7 +12587,7 @@ gtk_widget_set_accessible_role (GtkWidget *self, priv->accessible_role = role; if (priv->at_context != NULL) - g_object_set (priv->at_context, "accessible-role", priv->accessible_role, NULL); + gtk_at_context_set_accessible_role (priv->at_context, role); g_object_notify (G_OBJECT (self), "accessible-role"); } @@ -12586,15 +12608,10 @@ 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; - } + if (context != NULL && gtk_at_context_is_realized (context)) + return gtk_at_context_get_accessible_role (context); - return gtk_at_context_get_accessible_role (context); + return priv->accessible_role; } /** -- cgit v1.2.1 From 8157717e0375d526a110abc565ecb4c0a9fd1c89 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 19:36:38 +0000 Subject: a11y: Add missing fallback for accessible-role getter If the per-instance accessible role is unset, use the class role. --- gtk/gtkwidget.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 7c848040e3..4199ffd52d 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -12607,11 +12607,17 @@ 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)); + GtkWidgetClassPrivate *class_priv; if (context != NULL && gtk_at_context_is_realized (context)) return gtk_at_context_get_accessible_role (context); - return priv->accessible_role; + if (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET) + return priv->accessible_role; + + class_priv = GTK_WIDGET_GET_CLASS (self)->priv; + + return class_priv->accessible_role; } /** -- cgit v1.2.1 From 9ac4a7d99fa1ba9070befdfad7ab5afbf89000b3 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 11 Nov 2020 18:31:32 +0000 Subject: a11y: Simplify GtkModelButton Instead of recreating GtkATContexts in order to change their role, we can simply unrealize and realize them back. --- gtk/gtkmodelbutton.c | 57 +++++++++++++++------------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c index 6bcf11eb9b..c6e3d04f10 100644 --- a/gtk/gtkmodelbutton.c +++ b/gtk/gtkmodelbutton.c @@ -176,8 +176,6 @@ struct _GtkModelButton guint open_timeout; GtkEventController *controller; - GtkATContext *at_context; - guint active : 1; guint centered : 1; guint iconic : 1; @@ -194,10 +192,7 @@ struct _GtkModelButtonClass static void gtk_model_button_actionable_iface_init (GtkActionableInterface *iface); -static void gtk_model_button_accessible_iface_init (GtkAccessibleInterface *iface); - G_DEFINE_TYPE_WITH_CODE (GtkModelButton, gtk_model_button, GTK_TYPE_WIDGET, - G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE, gtk_model_button_accessible_iface_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_model_button_actionable_iface_init)) GType @@ -302,12 +297,20 @@ gtk_model_button_actionable_iface_init (GtkActionableInterface *iface) iface->set_action_target_value = gtk_model_button_set_action_target_value; } -static GtkATContext * -create_at_context (GtkModelButton *button, - GtkATContext *old_context) +static void +update_at_context (GtkModelButton *button) { - GdkDisplay *display = _gtk_widget_get_display (GTK_WIDGET (button)); GtkAccessibleRole role; + GtkATContext *context; + gboolean was_realized; + + context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (button)); + if (context == NULL) + return; + + was_realized = gtk_at_context_is_realized (context); + + gtk_at_context_unrealize (context); switch (button->role) { @@ -324,30 +327,10 @@ create_at_context (GtkModelButton *button, break; } - if (old_context != NULL) - return gtk_at_context_clone (old_context, role, GTK_ACCESSIBLE (button), display); - - return gtk_at_context_create (role, GTK_ACCESSIBLE (button), display); -} - -static GtkATContext * -gtk_model_button_get_at_context (GtkAccessible *accessible) -{ - GtkModelButton *button = GTK_MODEL_BUTTON (accessible); - - if (button->at_context == NULL) - button->at_context = create_at_context (button, NULL); - - return button->at_context; -} - -static void -gtk_model_button_accessible_iface_init (GtkAccessibleInterface *iface) -{ - GtkAccessibleInterface *parent_iface = g_type_interface_peek_parent (iface); + gtk_at_context_set_accessible_role (context, role); - iface->get_at_context = gtk_model_button_get_at_context; - iface->get_platform_state = parent_iface->get_platform_state; + if (was_realized) + gtk_at_context_realize (context); } static void @@ -610,8 +593,6 @@ static void gtk_model_button_set_role (GtkModelButton *self, GtkButtonRole role) { - GtkATContext *old_context; - if (role == self->role) return; @@ -631,11 +612,7 @@ gtk_model_button_set_role (GtkModelButton *self, update_node_name (self); gtk_model_button_update_state (self); - /* Replace the old context, if any, with a new context */ - old_context = g_steal_pointer (&self->at_context); - self->at_context = create_at_context (self, old_context); - g_clear_object (&old_context); - + update_at_context (self); update_accessible_properties (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ROLE]); @@ -1033,8 +1010,6 @@ gtk_model_button_dispose (GObject *object) g_clear_pointer (&model_button->menu_name, g_free); - g_clear_object (&model_button->at_context); - G_OBJECT_CLASS (gtk_model_button_parent_class)->dispose (object); } -- cgit v1.2.1 From 08d59d3f6820d41de8a2080e358eee2df77bcec3 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 12 Nov 2020 00:36:32 +0000 Subject: docs: Add "Accessibility" section to various widgets There are a few widgets that gained an accessible role, which means adding an "Accessibility" section in their description. --- gtk/gtkbox.c | 4 ++++ gtk/gtkcenterbox.c | 4 ++++ gtk/gtkenums.h | 3 ++- gtk/gtkgrid.c | 6 +++++- gtk/gtkheaderbar.c | 12 ++++++++---- gtk/gtknotebook.c | 29 ++++++++++++++++------------- gtk/gtkscrolledwindow.c | 4 ++++ gtk/gtkviewport.c | 6 +++++- gtk/gtkwindow.c | 2 +- gtk/gtkwindowcontrols.c | 4 ++++ gtk/gtkwindowhandle.c | 6 +++++- 11 files changed, 58 insertions(+), 22 deletions(-) diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c index 39aafdecd8..957678a3c0 100644 --- a/gtk/gtkbox.c +++ b/gtk/gtkbox.c @@ -51,6 +51,10 @@ * # CSS nodes * * GtkBox uses a single CSS node with name box. + * + * # Accessibility + * + * GtkBox uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ #include "config.h" diff --git a/gtk/gtkcenterbox.c b/gtk/gtkcenterbox.c index 097d135017..9ea5a241e0 100644 --- a/gtk/gtkcenterbox.c +++ b/gtk/gtkcenterbox.c @@ -50,6 +50,10 @@ * * In vertical orientation, the nodes of the children are arranged from top to * bottom. + * + * # Accessibility + * + * GtkCenterBox uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ #include "config.h" diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index 8f0f7edc98..206fdbef12 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -1136,7 +1136,8 @@ typedef enum { * @GTK_ACCESSIBLE_ROLE_GENERIC: Unused * @GTK_ACCESSIBLE_ROLE_GRID: A grid of items. * @GTK_ACCESSIBLE_ROLE_GRID_CELL: An item in a grid or tree grid. - * @GTK_ACCESSIBLE_ROLE_GROUP: Unused + * @GTK_ACCESSIBLE_ROLE_GROUP: An element that groups multiple widgets. GTK uses + * this role for various containers, like #GtkBox, #GtkViewport, and #GtkHeaderBar. * @GTK_ACCESSIBLE_ROLE_HEADING: Unused * @GTK_ACCESSIBLE_ROLE_IMG: An image. * @GTK_ACCESSIBLE_ROLE_INPUT: Abstract role. diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c index 4c21f29806..4f8d35492e 100644 --- a/gtk/gtkgrid.c +++ b/gtk/gtkgrid.c @@ -50,7 +50,11 @@ * * # CSS nodes * - * GtkGrid uses a single CSS node with name grid. + * GtkGrid uses a single CSS node with name `grid`. + * + * # Accessibility + * + * GtkGrid uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ typedef struct diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c index 745d5ce672..9006bea9e0 100644 --- a/gtk/gtkheaderbar.c +++ b/gtk/gtkheaderbar.c @@ -96,13 +96,17 @@ * ╰── windowcontrols.end * ]| * - * A #GtkHeaderBar's CSS node is called headerbar. It contains a windowhandle - * subnode, which contains a box subnode, which contains two box subnodes at - * the start and end of the headerbar, as well as a center node that represents + * A #GtkHeaderBar's CSS node is called `headerbar`. It contains a `windowhandle` + * subnode, which contains a `box` subnode, which contains two `box` subnodes at + * the start and end of the header bar, as well as a center node that represents * the title. * - * Each of the boxes contains a windowcontrols subnode, see #GtkWindowControls + * Each of the boxes contains a `windowcontrols` subnode, see #GtkWindowControls * for details, as well as other children. + * + * # Accessibility + * + * GtkHeaderBar uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ #define MIN_TITLE_CHARS 5 diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 945a13da6a..4daddb7b76 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -126,30 +126,33 @@ * ╰── * ]| * - * GtkNotebook has a main CSS node with name notebook, a subnode - * with name header and below that a subnode with name tabs which - * contains one subnode per tab with name tab. + * GtkNotebook has a main CSS node with name `notebook`, a subnode + * with name `header` and below that a subnode with name `tabs` which + * contains one subnode per tab with name `tab`. * * If action widgets are present, their CSS nodes are placed next - * to the tabs node. If the notebook is scrollable, CSS nodes with - * name arrow are placed as first and last child of the tabs node. + * to the `tabs` node. If the notebook is scrollable, CSS nodes with + * name `arrow` are placed as first and last child of the `tabs` node. * - * The main node gets the .frame style class when the notebook + * The main node gets the `.frame` style class when the notebook * has a border (see gtk_notebook_set_show_border()). * - * The header node gets one of the style class .top, .bottom, - * .left or .right, depending on where the tabs are placed. For - * reorderable pages, the tab node gets the .reorderable-page class. + * The header node gets one of the style class `.top`, `.bottom`, + * `.left` or `.right`, depending on where the tabs are placed. For + * reorderable pages, the tab node gets the `.reorderable-page` class. * - * A tab node gets the .dnd style class while it is moved with drag-and-drop. + * A `tab` node gets the `.dnd` style class while it is moved with drag-and-drop. * * The nodes are always arranged from left-to-right, regardless of text direction. * * # Accessibility * - * GtkNotebook uses the #GTK_ACCESSIBLE_ROLE_TAB_LIST and - * #GTK_ACCESSIBLE_ROLE_TAB roles for its list of tabs and the - * #GTK_ACCESSIBLE_ROLE_TAB_PANEL for the pages. + * GtkNotebook uses the following roles: + * + * - %GTK_ACCESSIBLE_ROLE_GROUP for the notebook widget + * - %GTK_ACCESSIBLE_ROLE_TAB_LIST for the list of tabs + * - %GTK_ACCESSIBLE_ROLE_TAB role for each tab + * - %GTK_ACCESSIBLE_ROLE_TAB_PANEL for each page */ diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c index 52a8ac77d4..09624cdc02 100644 --- a/gtk/gtkscrolledwindow.c +++ b/gtk/gtkscrolledwindow.c @@ -142,6 +142,10 @@ * * If both scrollbars are visible, the area where they meet is drawn * with a subnode named junction. + * + * # Accessibility + * + * GtkScrolledWindow uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c index 8fdef6123d..42bf850864 100644 --- a/gtk/gtkviewport.c +++ b/gtk/gtkviewport.c @@ -53,7 +53,11 @@ * * # CSS nodes * - * GtkViewport has a single CSS node with name viewport. + * GtkViewport has a single CSS node with name `viewport`. + * + * # Accessibility + * + * GtkViewport uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ typedef struct _GtkViewportPrivate GtkViewportPrivate; diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 68889591e7..085e54b788 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -142,7 +142,7 @@ * * # Accessibility * - * GtkWindow uses the #GTK_ACCESSIBLE_ROLE_WINDOW role. + * GtkWindow uses the %GTK_ACCESSIBLE_ROLE_WINDOW role. */ #define MENU_BAR_ACCEL GDK_KEY_F10 diff --git a/gtk/gtkwindowcontrols.c b/gtk/gtkwindowcontrols.c index 7278dfafff..553cbbdf0f 100644 --- a/gtk/gtkwindowcontrols.c +++ b/gtk/gtkwindowcontrols.c @@ -79,6 +79,10 @@ * and #GtkWindowControls:decoration-layout value. * * When #GtkWindowControls:empty is %TRUE, it gets the .empty style class. + * + * # Accessibility + * + * GtkWindowHandle uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ struct _GtkWindowControls { diff --git a/gtk/gtkwindowhandle.c b/gtk/gtkwindowhandle.c index fca0c3440d..5a6beeb273 100644 --- a/gtk/gtkwindowhandle.c +++ b/gtk/gtkwindowhandle.c @@ -48,7 +48,11 @@ * * # CSS nodes * - * #GtkWindowHandle has a single CSS node with the name windowhandle. + * #GtkWindowHandle has a single CSS node with the name `windowhandle`. + * + * # Accessibility + * + * GtkWindowHandle uses the %GTK_ACCESSIBLE_ROLE_GROUP role. */ struct _GtkWindowHandle { -- cgit v1.2.1