Merge branch 'ebassi/for-master' into 'master'

ATContext lifetime fixes

Closes #3341

See merge request GNOME/gtk!2811
This commit is contained in:
Matthias Clasen 2020-11-12 12:35:23 +00:00
commit 5d9799d4e3
23 changed files with 336 additions and 156 deletions

View File

@ -26,7 +26,9 @@
#include "gtkatspiprivate.h" #include "gtkatspiprivate.h"
#include "gtkatspiutilsprivate.h" #include "gtkatspiutilsprivate.h"
#include "gtkaccessibleprivate.h" #include "gtkaccessibleprivate.h"
#include "gtkpopover.h"
#include "gtkwidget.h" #include "gtkwidget.h"
#include "gtkwindow.h"
#include "a11y/atspi/atspi-component.h" #include "a11y/atspi/atspi-component.h"
@ -194,11 +196,20 @@ component_handle_method (GDBusConnection *connection,
} }
else if (g_strcmp0 (method_name, "GetLayer") == 0) 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) 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) 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) 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) else if (g_strcmp0 (method_name, "SetExtents") == 0)
{ {

View File

@ -46,9 +46,10 @@
#include "gtkeditable.h" #include "gtkeditable.h"
#include "gtkentryprivate.h" #include "gtkentryprivate.h"
#include "gtkroot.h" #include "gtkroot.h"
#include "gtktextview.h"
#include "gtkwindow.h"
#include "gtkstack.h" #include "gtkstack.h"
#include "gtktextview.h"
#include "gtktypebuiltins.h"
#include "gtkwindow.h"
#include <gio/gio.h> #include <gio/gio.h>
@ -411,7 +412,11 @@ get_parent_context_ref (GtkAccessible *accessible)
gtk_accessible_get_at_context (GTK_ACCESSIBLE (page)); gtk_accessible_get_at_context (GTK_ACCESSIBLE (page));
if (parent_context != NULL) 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 else
{ {
@ -1399,6 +1404,8 @@ gtk_at_spi_context_finalize (GObject *gobject)
gtk_at_spi_context_unregister_object (self); gtk_at_spi_context_unregister_object (self);
g_clear_object (&self->root);
g_free (self->bus_address); g_free (self->bus_address);
g_free (self->context_path); g_free (self->context_path);
@ -1447,8 +1454,8 @@ static void
gtk_at_spi_context_constructed (GObject *gobject) gtk_at_spi_context_constructed (GObject *gobject)
{ {
GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (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); g_assert (self->bus_address);
/* We use the application's object path to build the path of each /* We use the application's object path to build the path of each
@ -1490,10 +1497,19 @@ gtk_at_spi_context_constructed (GObject *gobject)
g_free (base_path); g_free (base_path);
g_free (uuid); 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 /* Every GTK application has a single root AT-SPI object, which
* handles all the global state, including the cache of accessible * handles all the global state, including the cache of accessible
* objects. We use the GdkDisplay to store it, so it's guaranteed * 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 = self->root =
g_object_get_data (G_OBJECT (display), "-gtk-atspi-root"); g_object_get_data (G_OBJECT (display), "-gtk-atspi-root");
@ -1502,26 +1518,32 @@ gtk_at_spi_context_constructed (GObject *gobject)
{ {
self->root = gtk_at_spi_root_new (self->bus_address); self->root = gtk_at_spi_root_new (self->bus_address);
g_object_set_data_full (G_OBJECT (display), "-gtk-atspi-root", g_object_set_data_full (G_OBJECT (display), "-gtk-atspi-root",
self->root, g_object_ref (self->root),
g_object_unref); g_object_unref);
} }
else
G_OBJECT_CLASS (gtk_at_spi_context_parent_class)->constructed (gobject); {
} g_object_ref (self->root);
}
static void
gtk_at_spi_context_realize (GtkATContext *context)
{
GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
self->connection = gtk_at_spi_root_get_connection (self->root); self->connection = gtk_at_spi_root_get_connection (self->root);
if (self->connection == NULL) if (self->connection == NULL)
return; return;
GtkAccessible *accessible = gtk_at_context_get_accessible (context); GtkAccessible *accessible = gtk_at_context_get_accessible (context);
GTK_NOTE (A11Y, g_message ("Realizing ATSPI context at '%s' for accessible '%s'",
self->context_path, #ifdef G_ENABLE_DEBUG
G_OBJECT_TYPE_NAME (accessible))); 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, gtk_atspi_connect_text_signals (accessible,
(GtkAtspiTextChangedCallback *)emit_text_changed, (GtkAtspiTextChangedCallback *)emit_text_changed,
@ -1551,6 +1573,8 @@ gtk_at_spi_context_unrealize (GtkATContext *context)
gtk_atspi_disconnect_text_signals (accessible); gtk_atspi_disconnect_text_signals (accessible);
gtk_atspi_disconnect_selection_signals (accessible); gtk_atspi_disconnect_selection_signals (accessible);
gtk_at_spi_context_unregister_object (self); gtk_at_spi_context_unregister_object (self);
g_clear_object (&self->root);
} }
static void static void

View File

@ -252,4 +252,16 @@ typedef enum {
ATSPI_COORD_TYPE_PARENT, ATSPI_COORD_TYPE_PARENT,
} AtspiCoordType; } 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 G_END_DECLS

View File

@ -80,7 +80,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role)
break; break;
case GTK_ACCESSIBLE_ROLE_FORM: case GTK_ACCESSIBLE_ROLE_FORM:
break; return ATSPI_ROLE_FORM;
case GTK_ACCESSIBLE_ROLE_GENERIC: case GTK_ACCESSIBLE_ROLE_GENERIC:
break; break;
@ -92,10 +92,10 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role)
return ATSPI_ROLE_TABLE_CELL; return ATSPI_ROLE_TABLE_CELL;
case GTK_ACCESSIBLE_ROLE_GROUP: case GTK_ACCESSIBLE_ROLE_GROUP:
break; return ATSPI_ROLE_PANEL;
case GTK_ACCESSIBLE_ROLE_HEADING: case GTK_ACCESSIBLE_ROLE_HEADING:
break; return ATSPI_ROLE_HEADING;
case GTK_ACCESSIBLE_ROLE_IMG: case GTK_ACCESSIBLE_ROLE_IMG:
return ATSPI_ROLE_IMAGE; return ATSPI_ROLE_IMAGE;
@ -110,7 +110,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role)
break; break;
case GTK_ACCESSIBLE_ROLE_LEGEND: case GTK_ACCESSIBLE_ROLE_LEGEND:
break; return ATSPI_ROLE_LABEL;
case GTK_ACCESSIBLE_ROLE_LINK: case GTK_ACCESSIBLE_ROLE_LINK:
return ATSPI_ROLE_LINK; return ATSPI_ROLE_LINK;
@ -134,7 +134,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role)
return ATSPI_ROLE_MARQUEE; return ATSPI_ROLE_MARQUEE;
case GTK_ACCESSIBLE_ROLE_MATH: case GTK_ACCESSIBLE_ROLE_MATH:
return ATSPI_ROLE_MATH;; return ATSPI_ROLE_MATH;
case GTK_ACCESSIBLE_ROLE_METER: case GTK_ACCESSIBLE_ROLE_METER:
return ATSPI_ROLE_LEVEL_BAR; return ATSPI_ROLE_LEVEL_BAR;
@ -269,7 +269,7 @@ gtk_accessible_role_to_atspi_role (GtkAccessibleRole role)
return ATSPI_ROLE_FILLER; return ATSPI_ROLE_FILLER;
case GTK_ACCESSIBLE_ROLE_WINDOW: case GTK_ACCESSIBLE_ROLE_WINDOW:
return ATSPI_ROLE_WINDOW; return ATSPI_ROLE_FRAME;
default: default:
break; break;
@ -294,6 +294,7 @@ gtk_atspi_role_for_context (GtkATContext *context)
GtkAccessible *accessible = gtk_at_context_get_accessible (context); GtkAccessible *accessible = gtk_at_context_get_accessible (context);
GtkAccessibleRole role = gtk_at_context_get_accessible_role (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)) if (GTK_IS_PASSWORD_ENTRY (accessible))
return ATSPI_ROLE_PASSWORD_TEXT; return ATSPI_ROLE_PASSWORD_TEXT;

View File

@ -104,13 +104,17 @@ gtk_accessible_get_at_context (GtkAccessible *self)
GtkAccessibleRole GtkAccessibleRole
gtk_accessible_get_accessible_role (GtkAccessible *self) gtk_accessible_get_accessible_role (GtkAccessible *self)
{ {
GtkAccessibleRole role;
g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), GTK_ACCESSIBLE_ROLE_NONE); g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), GTK_ACCESSIBLE_ROLE_NONE);
GtkATContext *context = gtk_accessible_get_at_context (self); GtkATContext *context = gtk_accessible_get_at_context (self);
if (context == NULL) if (context != NULL && gtk_at_context_is_realized (context))
return GTK_ACCESSIBLE_ROLE_NONE; return gtk_at_context_get_accessible_role (context);
return gtk_at_context_get_accessible_role (context); g_object_get (G_OBJECT (self), "accessible-role", &role, NULL);
return role;
} }
/** /**
@ -678,9 +682,7 @@ gtk_accessible_platform_changed (GtkAccessible *self,
/* propagate changes up from ignored widgets */ /* propagate changes up from ignored widgets */
if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE) 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) if (context == NULL)
return; return;
@ -765,6 +767,9 @@ gtk_accessible_should_present (GtkAccessible *self)
return FALSE; return FALSE;
context = gtk_accessible_get_at_context (self); context = gtk_accessible_get_at_context (self);
if (context == NULL)
return FALSE;
if (gtk_at_context_has_accessible_state (context, GTK_ACCESSIBLE_STATE_HIDDEN)) if (gtk_at_context_has_accessible_state (context, GTK_ACCESSIBLE_STATE_HIDDEN))
{ {
GtkAccessibleValue *value; GtkAccessibleValue *value;

View File

@ -176,6 +176,7 @@ gtk_aspect_frame_class_init (GtkAspectFrameClass *class)
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("aspectframe")); 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 static void

View File

@ -111,7 +111,7 @@ gtk_at_context_set_property (GObject *gobject,
break; break;
case PROP_DISPLAY: case PROP_DISPLAY:
self->display = g_value_get_object (value); gtk_at_context_set_display (self, g_value_get_object (value));
break; break;
default: default:
@ -245,8 +245,8 @@ gtk_at_context_class_init (GtkATContextClass *klass)
"The display connection", "The display connection",
GDK_TYPE_DISPLAY, GDK_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS |
G_PARAM_STATIC_STRINGS); G_PARAM_EXPLICIT_NOTIFY);
/** /**
* GtkATContext::state-change: * GtkATContext::state-change:
@ -385,15 +385,15 @@ gtk_at_context_init (GtkATContext *self)
self->accessible_role = GTK_ACCESSIBLE_ROLE_NONE; self->accessible_role = GTK_ACCESSIBLE_ROLE_NONE;
self->properties = self->properties =
gtk_accessible_attribute_set_new (N_PROPERTIES, gtk_accessible_attribute_set_new (G_N_ELEMENTS (property_attrs),
property_attrs, property_attrs,
(GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_property); (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_property);
self->relations = self->relations =
gtk_accessible_attribute_set_new (N_RELATIONS, gtk_accessible_attribute_set_new (G_N_ELEMENTS (relation_attrs),
relation_attrs, relation_attrs,
(GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_relation); (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_relation);
self->states = self->states =
gtk_accessible_attribute_set_new (N_STATES, gtk_accessible_attribute_set_new (G_N_ELEMENTS (state_attrs),
state_attrs, state_attrs,
(GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_state); (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_state);
} }
@ -414,6 +414,30 @@ gtk_at_context_get_accessible (GtkATContext *self)
return self->accessible; 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: * gtk_at_context_get_accessible_role:
* @self: a #GtkATContext * @self: a #GtkATContext
@ -430,6 +454,34 @@ gtk_at_context_get_accessible_role (GtkATContext *self)
return self->accessible_role; 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 > /*< private >
* gtk_at_context_get_display: * gtk_at_context_get_display:
* @self: a #GtkATContext * @self: a #GtkATContext
@ -862,6 +914,27 @@ gtk_at_context_get_accessible_relation (GtkATContext *self,
return gtk_accessible_attribute_set_get_value (self->relations, relation); 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" */ /* See the WAI-ARIA § 4.3, "Accessible Name and Description Computation" */
static void static void
gtk_at_context_get_name_accumulate (GtkATContext *self, gtk_at_context_get_name_accumulate (GtkATContext *self,
@ -937,7 +1010,8 @@ gtk_at_context_get_name_accumulate (GtkATContext *self,
if (names->len != 0) if (names->len != 0)
return; 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)); g_ptr_array_add (names, (char *)G_OBJECT_TYPE_NAME (self->accessible));
} }

View File

@ -150,7 +150,11 @@ GtkATContext * gtk_at_context_clone (GtkATContext
GtkAccessible *accessible, GtkAccessible *accessible,
GdkDisplay *display); GdkDisplay *display);
void gtk_at_context_set_display (GtkATContext *self,
GdkDisplay *display);
GdkDisplay * gtk_at_context_get_display (GtkATContext *self); 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_realize (GtkATContext *self);
void gtk_at_context_unrealize (GtkATContext *self); void gtk_at_context_unrealize (GtkATContext *self);

View File

@ -51,6 +51,10 @@
* # CSS nodes * # CSS nodes
* *
* GtkBox uses a single CSS node with name box. * GtkBox uses a single CSS node with name box.
*
* # Accessibility
*
* GtkBox uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
*/ */
#include "config.h" #include "config.h"
@ -278,6 +282,7 @@ gtk_box_class_init (GtkBoxClass *class)
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); 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_css_name (widget_class, I_("box"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void
gtk_box_init (GtkBox *box) gtk_box_init (GtkBox *box)

View File

@ -50,6 +50,10 @@
* *
* In vertical orientation, the nodes of the children are arranged from top to * In vertical orientation, the nodes of the children are arranged from top to
* bottom. * bottom.
*
* # Accessibility
*
* GtkCenterBox uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
*/ */
#include "config.h" #include "config.h"
@ -210,6 +214,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_layout_manager_type (widget_class, GTK_TYPE_CENTER_LAYOUT);
gtk_widget_class_set_css_name (widget_class, I_("box")); gtk_widget_class_set_css_name (widget_class, I_("box"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void

View File

@ -1136,7 +1136,8 @@ typedef enum {
* @GTK_ACCESSIBLE_ROLE_GENERIC: Unused * @GTK_ACCESSIBLE_ROLE_GENERIC: Unused
* @GTK_ACCESSIBLE_ROLE_GRID: A grid of items. * @GTK_ACCESSIBLE_ROLE_GRID: A grid of items.
* @GTK_ACCESSIBLE_ROLE_GRID_CELL: An item in a grid or tree grid. * @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_HEADING: Unused
* @GTK_ACCESSIBLE_ROLE_IMG: An image. * @GTK_ACCESSIBLE_ROLE_IMG: An image.
* @GTK_ACCESSIBLE_ROLE_INPUT: Abstract role. * @GTK_ACCESSIBLE_ROLE_INPUT: Abstract role.

View File

@ -50,7 +50,11 @@
* *
* # CSS nodes * # 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 typedef struct
@ -395,8 +399,8 @@ gtk_grid_class_init (GtkGridClass *class)
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); 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_css_name (widget_class, I_("grid"));
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_GRID_LAYOUT); 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; static GtkBuildableIface *parent_buildable_iface;

View File

@ -96,13 +96,17 @@
* windowcontrols.end * windowcontrols.end
* ]| * ]|
* *
* A #GtkHeaderBar's CSS node is called headerbar. It contains a windowhandle * A #GtkHeaderBar's CSS node is called `headerbar`. It contains a `windowhandle`
* subnode, which contains a box subnode, which contains two box subnodes at * 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 * the start and end of the header bar, as well as a center node that represents
* the title. * 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. * for details, as well as other children.
*
* # Accessibility
*
* GtkHeaderBar uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
*/ */
#define MIN_TITLE_CHARS 5 #define MIN_TITLE_CHARS 5
@ -600,6 +604,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_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_css_name (widget_class, I_("headerbar")); gtk_widget_class_set_css_name (widget_class, I_("headerbar"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void

View File

@ -176,8 +176,6 @@ struct _GtkModelButton
guint open_timeout; guint open_timeout;
GtkEventController *controller; GtkEventController *controller;
GtkATContext *at_context;
guint active : 1; guint active : 1;
guint centered : 1; guint centered : 1;
guint iconic : 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_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_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)) G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_model_button_actionable_iface_init))
GType 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; iface->set_action_target_value = gtk_model_button_set_action_target_value;
} }
static GtkATContext * static void
create_at_context (GtkModelButton *button, update_at_context (GtkModelButton *button)
GtkATContext *old_context)
{ {
GdkDisplay *display = _gtk_widget_get_display (GTK_WIDGET (button));
GtkAccessibleRole role; 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) switch (button->role)
{ {
@ -324,30 +327,10 @@ create_at_context (GtkModelButton *button,
break; break;
} }
if (old_context != NULL) gtk_at_context_set_accessible_role (context, role);
return gtk_at_context_clone (old_context, role, GTK_ACCESSIBLE (button), display);
return gtk_at_context_create (role, GTK_ACCESSIBLE (button), display); if (was_realized)
} gtk_at_context_realize (context);
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);
iface->get_at_context = gtk_model_button_get_at_context;
iface->get_platform_state = parent_iface->get_platform_state;
} }
static void static void
@ -610,8 +593,6 @@ static void
gtk_model_button_set_role (GtkModelButton *self, gtk_model_button_set_role (GtkModelButton *self,
GtkButtonRole role) GtkButtonRole role)
{ {
GtkATContext *old_context;
if (role == self->role) if (role == self->role)
return; return;
@ -631,11 +612,7 @@ gtk_model_button_set_role (GtkModelButton *self,
update_node_name (self); update_node_name (self);
gtk_model_button_update_state (self); gtk_model_button_update_state (self);
/* Replace the old context, if any, with a new context */ update_at_context (self);
old_context = g_steal_pointer (&self->at_context);
self->at_context = create_at_context (self, old_context);
g_clear_object (&old_context);
update_accessible_properties (self); update_accessible_properties (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ROLE]); 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_pointer (&model_button->menu_name, g_free);
g_clear_object (&model_button->at_context);
G_OBJECT_CLASS (gtk_model_button_parent_class)->dispose (object); G_OBJECT_CLASS (gtk_model_button_parent_class)->dispose (object);
} }

View File

@ -126,30 +126,33 @@
* <child> * <child>
* ]| * ]|
* *
* GtkNotebook has a main CSS node with name notebook, a subnode * GtkNotebook has a main CSS node with name `notebook`, a subnode
* with name header and below that a subnode with name tabs which * with name `header` and below that a subnode with name `tabs` which
* contains one subnode per tab with name tab. * contains one subnode per tab with name `tab`.
* *
* If action widgets are present, their CSS nodes are placed next * If action widgets are present, their CSS nodes are placed next
* to the tabs node. If the notebook is scrollable, CSS nodes with * 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. * 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()). * has a border (see gtk_notebook_set_show_border()).
* *
* The header node gets one of the style class .top, .bottom, * The header node gets one of the style class `.top`, `.bottom`,
* .left or .right, depending on where the tabs are placed. For * `.left` or `.right`, depending on where the tabs are placed. For
* reorderable pages, the tab node gets the .reorderable-page class. * 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. * The nodes are always arranged from left-to-right, regardless of text direction.
* *
* # Accessibility * # Accessibility
* *
* GtkNotebook uses the #GTK_ACCESSIBLE_ROLE_TAB_LIST and * GtkNotebook uses the following roles:
* #GTK_ACCESSIBLE_ROLE_TAB roles for its list of tabs and the *
* #GTK_ACCESSIBLE_ROLE_TAB_PANEL for the pages. * - %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
*/ */
@ -1369,6 +1372,7 @@ gtk_notebook_class_init (GtkNotebookClass *class)
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); 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_css_name (widget_class, I_("notebook"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void

View File

@ -142,6 +142,10 @@
* *
* If both scrollbars are visible, the area where they meet is drawn * If both scrollbars are visible, the area where they meet is drawn
* with a subnode named junction. * with a subnode named junction.
*
* # Accessibility
*
* GtkScrolledWindow uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
*/ */
@ -868,6 +872,7 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
add_tab_bindings (widget_class, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD); 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_css_name (widget_class, I_("scrolledwindow"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static gboolean static gboolean

View File

@ -274,6 +274,8 @@ gtk_stack_page_finalize (GObject *object)
g_object_remove_weak_pointer (G_OBJECT (page->last_focus), g_object_remove_weak_pointer (G_OBJECT (page->last_focus),
(gpointer *)&page->last_focus); (gpointer *)&page->last_focus);
g_clear_object (&page->at_context);
G_OBJECT_CLASS (gtk_stack_page_parent_class)->finalize (object); G_OBJECT_CLASS (gtk_stack_page_parent_class)->finalize (object);
} }

View File

@ -118,15 +118,9 @@ gboolean
gtk_test_accessible_has_role (GtkAccessible *accessible, gtk_test_accessible_has_role (GtkAccessible *accessible,
GtkAccessibleRole role) GtkAccessibleRole role)
{ {
GtkATContext *context;
g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE); g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), FALSE);
context = gtk_accessible_get_at_context (accessible); return gtk_accessible_get_accessible_role (accessible) == role;
if (context == NULL)
return FALSE;
return gtk_at_context_get_accessible_role (context) == role;
} }
gboolean gboolean

View File

@ -53,7 +53,11 @@
* *
* # CSS nodes * # 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; typedef struct _GtkViewportPrivate GtkViewportPrivate;
@ -382,6 +386,7 @@ gtk_viewport_class_init (GtkViewportClass *class)
GTK_PARAM_READWRITE)); GTK_PARAM_READWRITE));
gtk_widget_class_set_css_name (widget_class, I_("viewport")); gtk_widget_class_set_css_name (widget_class, I_("viewport"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void

View File

@ -771,8 +771,6 @@ gtk_widget_base_class_init (gpointer g_class)
g_object_unref (shortcut); g_object_unref (shortcut);
} }
} }
priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET;
} }
static void static void
@ -1624,6 +1622,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
_gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECTv); _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECTv);
gtk_widget_class_set_css_name (klass, I_("widget")); gtk_widget_class_set_css_name (klass, I_("widget"));
gtk_widget_class_set_accessible_role (klass, GTK_ACCESSIBLE_ROLE_WIDGET);
} }
static void 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_event_controller_set_name (controller, "gtk-widget-class-shortcuts");
gtk_widget_add_controller (widget, controller); 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 void
@ -2330,15 +2357,7 @@ gtk_widget_root (GtkWidget *widget)
if (priv->layout_manager) if (priv->layout_manager)
gtk_layout_manager_set_root (priv->layout_manager, priv->root); gtk_layout_manager_set_root (priv->layout_manager, priv->root);
if (priv->at_context != NULL) gtk_widget_realize_at_context (widget);
{
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_GET_CLASS (widget)->root (widget); GTK_WIDGET_GET_CLASS (widget)->root (widget);
@ -2364,8 +2383,8 @@ gtk_widget_unroot (GtkWidget *widget)
GTK_WIDGET_GET_CLASS (widget)->unroot (widget); GTK_WIDGET_GET_CLASS (widget)->unroot (widget);
if (priv->at_context) gtk_at_context_set_display (priv->at_context, gdk_display_get_default ());
gtk_at_context_unrealize (priv->at_context); gtk_at_context_unrealize (priv->at_context);
if (priv->context) if (priv->context)
gtk_style_context_set_display (priv->context, gdk_display_get_default ()); gtk_style_context_set_display (priv->context, gdk_display_get_default ());
@ -7028,6 +7047,7 @@ gtk_widget_dispose (GObject *object)
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GSList *sizegroups; GSList *sizegroups;
GtkActionMuxer *muxer; GtkActionMuxer *muxer;
GtkATContext *at_context;
muxer = g_object_get_qdata (G_OBJECT (widget), quark_action_muxer); muxer = g_object_get_qdata (G_OBJECT (widget), quark_action_muxer);
if (muxer != NULL) if (muxer != NULL)
@ -7048,8 +7068,6 @@ gtk_widget_dispose (GObject *object)
gtk_layout_manager_set_widget (priv->layout_manager, NULL); gtk_layout_manager_set_widget (priv->layout_manager, NULL);
g_clear_object (&priv->layout_manager); g_clear_object (&priv->layout_manager);
g_clear_object (&priv->at_context);
priv->visible = FALSE; priv->visible = FALSE;
if (_gtk_widget_get_realized (widget)) if (_gtk_widget_get_realized (widget))
gtk_widget_unrealize (widget); gtk_widget_unrealize (widget);
@ -7074,6 +7092,10 @@ gtk_widget_dispose (GObject *object)
gtk_size_group_remove_widget (size_group, widget); 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_set_qdata (object, quark_action_muxer, NULL);
G_OBJECT_CLASS (gtk_widget_parent_class)->dispose (object); G_OBJECT_CLASS (gtk_widget_parent_class)->dispose (object);
@ -7235,6 +7257,7 @@ gtk_widget_finalize (GObject *object)
g_object_unref (priv->cssnode); g_object_unref (priv->cssnode);
g_clear_object (&priv->context); g_clear_object (&priv->context);
g_clear_object (&priv->at_context);
_gtk_size_request_cache_free (&priv->requests); _gtk_size_request_cache_free (&priv->requests);
@ -8103,34 +8126,37 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
{ {
GtkWidget *self = GTK_WIDGET (accessible); GtkWidget *self = GTK_WIDGET (accessible);
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); 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) if (priv->in_destruction)
return NULL;
if (priv->at_context == NULL)
{ {
GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self); GTK_NOTE (A11Y, g_message ("ATContext for widget “%s” [%p] accessed during destruction",
GtkWidgetClassPrivate *class_priv = widget_class->priv; G_OBJECT_TYPE_NAME (self),
GdkDisplay *display = _gtk_widget_get_display (self); self));
GtkAccessibleRole role; 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;
priv->accessible_role = role;
priv->at_context = gtk_at_context_create (role, accessible, display);
} }
if (priv->at_context != NULL)
return priv->at_context;
/* 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; return priv->at_context;
} }
@ -12559,7 +12585,7 @@ gtk_widget_set_accessible_role (GtkWidget *self,
priv->accessible_role = role; priv->accessible_role = role;
if (priv->at_context != NULL) 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"); g_object_notify (G_OBJECT (self), "accessible-role");
} }
@ -12579,16 +12605,17 @@ gtk_widget_get_accessible_role (GtkWidget *self)
{ {
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self)); GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (self));
GtkWidgetClassPrivate *class_priv;
if (context == NULL || !gtk_at_context_is_realized (context)) if (context != NULL && gtk_at_context_is_realized (context))
{ return gtk_at_context_get_accessible_role (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 (priv->accessible_role != GTK_ACCESSIBLE_ROLE_WIDGET)
} return priv->accessible_role;
return gtk_at_context_get_accessible_role (context); class_priv = GTK_WIDGET_GET_CLASS (self)->priv;
return class_priv->accessible_role;
} }
/** /**

View File

@ -142,7 +142,7 @@
* *
* # Accessibility * # Accessibility
* *
* GtkWindow uses the #GTK_ACCESSIBLE_ROLE_WINDOW role. * GtkWindow uses the %GTK_ACCESSIBLE_ROLE_WINDOW role.
*/ */
#define MENU_BAR_ACCEL GDK_KEY_F10 #define MENU_BAR_ACCEL GDK_KEY_F10
@ -1965,6 +1965,10 @@ gtk_window_set_title (GtkWindow *window,
if (_gtk_widget_get_realized (GTK_WIDGET (window))) if (_gtk_widget_get_realized (GTK_WIDGET (window)))
gdk_toplevel_set_title (GDK_TOPLEVEL (priv->surface), new_title != NULL ? new_title : ""); 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]); g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_TITLE]);
} }

View File

@ -79,6 +79,10 @@
* and #GtkWindowControls:decoration-layout value. * and #GtkWindowControls:decoration-layout value.
* *
* When #GtkWindowControls:empty is %TRUE, it gets the .empty style class. * When #GtkWindowControls:empty is %TRUE, it gets the .empty style class.
*
* # Accessibility
*
* GtkWindowHandle uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
*/ */
struct _GtkWindowControls { struct _GtkWindowControls {
@ -538,6 +542,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_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
gtk_widget_class_set_css_name (widget_class, I_("windowcontrols")); gtk_widget_class_set_css_name (widget_class, I_("windowcontrols"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void

View File

@ -48,7 +48,11 @@
* *
* # CSS nodes * # 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 { struct _GtkWindowHandle {
@ -550,6 +554,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_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_css_name (widget_class, I_("windowhandle")); gtk_widget_class_set_css_name (widget_class, I_("windowhandle"));
gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
} }
static void static void