summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-11-12 12:35:23 +0000
committerMatthias Clasen <mclasen@redhat.com>2020-11-12 12:35:23 +0000
commit5d9799d4e35d407ed151bae51f9295ffbf794476 (patch)
tree80b385423b3d69965537cf0fdbca721223b04a70
parentf95943a752679ffba36cd3387719f4388fb81810 (diff)
parent08d59d3f6820d41de8a2080e358eee2df77bcec3 (diff)
downloadgtk+-5d9799d4e35d407ed151bae51f9295ffbf794476.tar.gz
Merge branch 'ebassi/for-master' into 'master'
ATContext lifetime fixes Closes #3341 See merge request GNOME/gtk!2811
-rw-r--r--gtk/a11y/gtkatspicomponent.c19
-rw-r--r--gtk/a11y/gtkatspicontext.c56
-rw-r--r--gtk/a11y/gtkatspiprivate.h12
-rw-r--r--gtk/a11y/gtkatspiutils.c13
-rw-r--r--gtk/gtkaccessible.c17
-rw-r--r--gtk/gtkaspectframe.c1
-rw-r--r--gtk/gtkatcontext.c88
-rw-r--r--gtk/gtkatcontextprivate.h4
-rw-r--r--gtk/gtkbox.c5
-rw-r--r--gtk/gtkcenterbox.c5
-rw-r--r--gtk/gtkenums.h3
-rw-r--r--gtk/gtkgrid.c8
-rw-r--r--gtk/gtkheaderbar.c13
-rw-r--r--gtk/gtkmodelbutton.c57
-rw-r--r--gtk/gtknotebook.c30
-rw-r--r--gtk/gtkscrolledwindow.c5
-rw-r--r--gtk/gtkstack.c2
-rw-r--r--gtk/gtktestatcontext.c8
-rw-r--r--gtk/gtkviewport.c7
-rw-r--r--gtk/gtkwidget.c117
-rw-r--r--gtk/gtkwindow.c6
-rw-r--r--gtk/gtkwindowcontrols.c5
-rw-r--r--gtk/gtkwindowhandle.c7
23 files changed, 334 insertions, 154 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/gtkatspicontext.c b/gtk/a11y/gtkatspicontext.c
index 98bde0a0e7..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 <gio/gio.h>
@@ -411,7 +412,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
{
@@ -1399,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);
@@ -1447,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
@@ -1490,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");
@@ -1502,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,
@@ -1551,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
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
diff --git a/gtk/a11y/gtkatspiutils.c b/gtk/a11y/gtkatspiutils.c
index 7ec3193b9b..87b1887fe8 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;
@@ -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;
diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c
index 13c4cb35ed..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;
}
/**
@@ -678,9 +682,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 +767,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;
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/gtkatcontext.c b/gtk/gtkatcontext.c
index 661ac848b1..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
@@ -431,6 +455,34 @@ gtk_at_context_get_accessible_role (GtkATContext *self)
}
/*< 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
*
@@ -862,6 +914,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 +1010,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));
}
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/gtkbox.c b/gtk/gtkbox.c
index b23d523ac2..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"
@@ -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_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..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"
@@ -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_css_name (widget_class, I_("box"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
}
static void
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 3a5b6a7a95..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
@@ -395,8 +399,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..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
@@ -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_css_name (widget_class, I_("headerbar"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
}
static void
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);
}
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 6f96faeee1..4daddb7b76 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -126,30 +126,33 @@
* ╰── <child>
* ]|
*
- * 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
*/
@@ -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_css_name (widget_class, I_("notebook"));
+ 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..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.
*/
@@ -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);
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/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);
}
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
diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c
index 43df2cddae..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;
@@ -382,6 +386,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/gtkwidget.c b/gtk/gtkwidget.c
index 8d6e4067d5..861d87a0cf 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 ());
@@ -7028,6 +7047,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)
@@ -7048,8 +7068,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);
@@ -7074,6 +7092,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);
@@ -7235,6 +7257,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);
@@ -8103,33 +8126,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;
}
@@ -12559,7 +12585,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");
}
@@ -12579,16 +12605,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))
- {
- if (priv->accessible_role == GTK_ACCESSIBLE_ROLE_WIDGET)
- return gtk_widget_class_get_accessible_role (GTK_WIDGET_GET_CLASS (self));
+ 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 gtk_at_context_get_accessible_role (context);
+ return class_priv->accessible_role;
}
/**
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 6e8f289d0b..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
@@ -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]);
}
diff --git a/gtk/gtkwindowcontrols.c b/gtk/gtkwindowcontrols.c
index d2b3667555..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 {
@@ -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_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..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 {
@@ -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_css_name (widget_class, I_("windowhandle"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
}
static void