diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c index 74f368d5e7..8c49c27118 100644 --- a/gtk/gtkatcontext.c +++ b/gtk/gtkatcontext.c @@ -111,7 +111,7 @@ gtk_at_context_set_property (GObject *gobject, break; case PROP_DISPLAY: - self->display = g_value_get_object (value); + gtk_at_context_set_display (self, g_value_get_object (value)); break; default: @@ -245,8 +245,8 @@ gtk_at_context_class_init (GtkATContextClass *klass) "The display connection", GDK_TYPE_DISPLAY, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); /** * GtkATContext::state-change: @@ -385,15 +385,15 @@ gtk_at_context_init (GtkATContext *self) self->accessible_role = GTK_ACCESSIBLE_ROLE_NONE; self->properties = - gtk_accessible_attribute_set_new (N_PROPERTIES, + gtk_accessible_attribute_set_new (G_N_ELEMENTS (property_attrs), property_attrs, (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_property); self->relations = - gtk_accessible_attribute_set_new (N_RELATIONS, + gtk_accessible_attribute_set_new (G_N_ELEMENTS (relation_attrs), relation_attrs, (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_relation); self->states = - gtk_accessible_attribute_set_new (N_STATES, + gtk_accessible_attribute_set_new (G_N_ELEMENTS (state_attrs), state_attrs, (GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_state); } @@ -414,6 +414,30 @@ gtk_at_context_get_accessible (GtkATContext *self) return self->accessible; } +/*< private > + * gtk_at_context_set_accessible_role: + * @self: a #GtkATContext + * @role: the accessible role for the context + * + * Sets the accessible role for the given #GtkATContext. + * + * This function can only be called if the #GtkATContext is unrealized. + */ +void +gtk_at_context_set_accessible_role (GtkATContext *self, + GtkAccessibleRole role) +{ + g_return_if_fail (GTK_IS_AT_CONTEXT (self)); + g_return_if_fail (!self->realized); + + if (self->accessible_role == role) + return; + + self->accessible_role = role; + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACCESSIBLE_ROLE]); +} + /** * gtk_at_context_get_accessible_role: * @self: a #GtkATContext @@ -430,6 +454,34 @@ gtk_at_context_get_accessible_role (GtkATContext *self) return self->accessible_role; } +/*< private > + * gtk_at_context_set_display: + * @self: a #GtkATContext + * @display: a #GdkDisplay + * + * Sets the #GdkDisplay used by the #GtkATContext. + * + * This function can only be called if the #GtkATContext is + * not realized. + */ +void +gtk_at_context_set_display (GtkATContext *self, + GdkDisplay *display) +{ + g_return_if_fail (GTK_IS_AT_CONTEXT (self)); + g_return_if_fail (display == NULL || GDK_IS_DISPLAY (display)); + + if (self->display == display) + return; + + if (self->realized) + return; + + self->display = display; + + g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DISPLAY]); +} + /*< private > * gtk_at_context_get_display: * @self: a #GtkATContext diff --git a/gtk/gtkatcontextprivate.h b/gtk/gtkatcontextprivate.h index f1b62f8cb8..d9678cbea5 100644 --- a/gtk/gtkatcontextprivate.h +++ b/gtk/gtkatcontextprivate.h @@ -150,7 +150,11 @@ GtkATContext * gtk_at_context_clone (GtkATContext GtkAccessible *accessible, GdkDisplay *display); +void gtk_at_context_set_display (GtkATContext *self, + GdkDisplay *display); GdkDisplay * gtk_at_context_get_display (GtkATContext *self); +void gtk_at_context_set_accessible_role (GtkATContext *self, + GtkAccessibleRole role); void gtk_at_context_realize (GtkATContext *self); void gtk_at_context_unrealize (GtkATContext *self); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 48a394a766..7c848040e3 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -771,8 +771,6 @@ gtk_widget_base_class_init (gpointer g_class) g_object_unref (shortcut); } } - - priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET; } static void @@ -1624,6 +1622,7 @@ gtk_widget_class_init (GtkWidgetClass *klass) _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECTv); gtk_widget_class_set_css_name (klass, I_("widget")); + gtk_widget_class_set_accessible_role (klass, GTK_ACCESSIBLE_ROLE_WIDGET); } static void @@ -2300,6 +2299,34 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class) gtk_event_controller_set_name (controller, "gtk-widget-class-shortcuts"); gtk_widget_add_controller (widget, controller); } + + priv->at_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget)); +} + +static void +gtk_widget_realize_at_context (GtkWidget *self) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self); + GtkAccessibleRole role = priv->accessible_role; + + if (gtk_at_context_is_realized (priv->at_context)) + return; + + /* Realize the root ATContext first */ + if (!GTK_IS_ROOT (self)) + gtk_widget_realize_at_context (GTK_WIDGET (priv->root)); + + /* Reset the accessible role to its current value */ + if (role == GTK_ACCESSIBLE_ROLE_WIDGET) + { + GtkWidgetClassPrivate *class_priv = GTK_WIDGET_GET_CLASS (self)->priv; + + role = class_priv->accessible_role; + } + + gtk_at_context_set_accessible_role (priv->at_context, role); + gtk_at_context_set_display (priv->at_context, gtk_root_get_display (priv->root)); + gtk_at_context_realize (priv->at_context); } void @@ -2330,15 +2357,7 @@ gtk_widget_root (GtkWidget *widget) if (priv->layout_manager) gtk_layout_manager_set_root (priv->layout_manager, priv->root); - if (priv->at_context != NULL) - { - GtkATContext *root_context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (priv->root)); - - if (root_context) - gtk_at_context_realize (root_context); - - gtk_at_context_realize (priv->at_context); - } + gtk_widget_realize_at_context (widget); GTK_WIDGET_GET_CLASS (widget)->root (widget); @@ -2364,8 +2383,8 @@ gtk_widget_unroot (GtkWidget *widget) GTK_WIDGET_GET_CLASS (widget)->unroot (widget); - if (priv->at_context) - gtk_at_context_unrealize (priv->at_context); + gtk_at_context_set_display (priv->at_context, gdk_display_get_default ()); + gtk_at_context_unrealize (priv->at_context); if (priv->context) gtk_style_context_set_display (priv->context, gdk_display_get_default ()); @@ -8109,34 +8128,37 @@ 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; - - /* 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); + GTK_NOTE (A11Y, g_message ("ATContext for widget ā€œ%sā€ [%p] accessed during destruction", + G_OBJECT_TYPE_NAME (self), + self)); + return NULL; } + 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; } @@ -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)); + if (context != NULL && gtk_at_context_is_realized (context)) + return gtk_at_context_get_accessible_role (context); - return priv->accessible_role; - } - - return gtk_at_context_get_accessible_role (context); + return priv->accessible_role; } /**