summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2020-11-11 18:17:41 +0000
committerEmmanuele Bassi <ebassi@gnome.org>2020-11-11 19:45:43 +0000
commit9052f6dafe15082aa05e25c0267b30f668488e9f (patch)
tree90c2b7939488b4ff1dda622aa030bcc0de6db546
parent292576f3129a1bd73d3b5b4ad0e41d70df1c805e (diff)
downloadgtk+-9052f6dafe15082aa05e25c0267b30f668488e9f.tar.gz
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.
-rw-r--r--gtk/gtkatcontext.c64
-rw-r--r--gtk/gtkatcontextprivate.h4
-rw-r--r--gtk/gtkwidget.c105
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
@@ -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
*
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;
}
/**