Commit 9052f6da authored by Emmanuele Bassi's avatar Emmanuele Bassi
Browse files

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.
parent 292576f3
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment