diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c index 8cace46611..4f90d04e24 100644 --- a/gtk/gtkaccessible.c +++ b/gtk/gtkaccessible.c @@ -276,3 +276,90 @@ gtk_accessible_update_property_value (GtkAccessible *self, gtk_accessible_value_unref (real_value); gtk_at_context_update (context); } + +/** + * gtk_accessible_update_relation: + * @self: a #GtkAccessible + * @first_relation: the first #GtkAccessibleRelation + * @...: a list of relation and value pairs, terminated by -1 + * + * Updates a list of accessible relations. + * + * This function should be called by #GtkWidget types whenever an accessible + * relation change must be communicated to assistive technologies. + */ +void +gtk_accessible_update_relation (GtkAccessible *self, + GtkAccessibleRelation first_relation, + ...) +{ + GtkAccessibleRelation relation; + GtkATContext *context; + va_list args; + + g_return_if_fail (GTK_IS_ACCESSIBLE (self)); + + context = gtk_accessible_get_at_context (self); + if (context == NULL) + return; + + va_start (args, first_relation); + + relation = first_relation; + + while (relation != -1) + { + GtkAccessibleValue *value = gtk_accessible_value_collect_for_relation (relation, &args); + + /* gtk_accessible_value_collect_for_relation() will warn for us */ + if (value == NULL) + goto out; + + gtk_at_context_set_accessible_relation (context, relation, value); + gtk_accessible_value_unref (value); + + relation = va_arg (args, int); + } + + gtk_at_context_update (context); + +out: + va_end (args); +} + +/** + * gtk_accessible_update_relation_value: + * @self: a #GtkAccessible + * @relation: a #GtkAccessibleRelation + * @value: a #GValue with the value for @relation + * + * Updates an accessible relation. + * + * This function should be called by #GtkWidget types whenever an accessible + * relation change must be communicated to assistive technologies. + * + * This function is meant to be used by language bindings. + */ +void +gtk_accessible_update_relation_value (GtkAccessible *self, + GtkAccessibleRelation relation, + const GValue *value) +{ + GtkATContext *context; + + g_return_if_fail (GTK_IS_ACCESSIBLE (self)); + + context = gtk_accessible_get_at_context (self); + if (context == NULL) + return; + + GtkAccessibleValue *real_value = + gtk_accessible_value_collect_for_relation_value (relation, value); + + if (real_value == NULL) + return; + + gtk_at_context_set_accessible_relation (context, relation, real_value); + gtk_accessible_value_unref (real_value); + gtk_at_context_update (context); +} diff --git a/gtk/gtkaccessible.h b/gtk/gtkaccessible.h index 9ad56784c7..d0a115d205 100644 --- a/gtk/gtkaccessible.h +++ b/gtk/gtkaccessible.h @@ -43,6 +43,10 @@ void gtk_accessible_update_property (GtkAccessible GtkAccessibleProperty first_property, ...); GDK_AVAILABLE_IN_ALL +void gtk_accessible_update_relation (GtkAccessible *self, + GtkAccessibleRelation first_relation, + ...); +GDK_AVAILABLE_IN_ALL void gtk_accessible_update_state_value (GtkAccessible *self, GtkAccessibleState state, const GValue *value); @@ -50,5 +54,9 @@ GDK_AVAILABLE_IN_ALL void gtk_accessible_update_property_value (GtkAccessible *self, GtkAccessibleProperty property, const GValue *value); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_update_relation_value (GtkAccessible *self, + GtkAccessibleRelation relation, + const GValue *value); G_END_DECLS diff --git a/gtk/gtkaccessiblerelationset.c b/gtk/gtkaccessiblerelationset.c new file mode 100644 index 0000000000..2e6a64b41f --- /dev/null +++ b/gtk/gtkaccessiblerelationset.c @@ -0,0 +1,217 @@ +/* gtkaccessiblerelationset.c: Accessible relation set + * + * Copyright 2020 GNOME Foundation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "config.h" + +#include "gtkaccessiblerelationsetprivate.h" + +#include "gtkbitmaskprivate.h" +#include "gtkenums.h" + +/* Keep in sync with GtkAccessibleRelation in gtkenums.h */ +#define LAST_RELATION GTK_ACCESSIBLE_RELATION_SET_SIZE + +struct _GtkAccessibleRelationSet +{ + GtkBitmask *relation_set; + + GtkAccessibleValue **relation_values; +}; + +static GtkAccessibleRelationSet * +gtk_accessible_relation_set_init (GtkAccessibleRelationSet *self) +{ + self->relation_set = _gtk_bitmask_new (); + self->relation_values = g_new (GtkAccessibleValue *, LAST_RELATION); + + /* Initialize all relation values, so we can always get the full set */ + for (int i = 0; i < LAST_RELATION; i++) + self->relation_values[i] = gtk_accessible_value_get_default_for_relation (i); + + return self; +} + +GtkAccessibleRelationSet * +gtk_accessible_relation_set_new (void) +{ + GtkAccessibleRelationSet *set = g_rc_box_new0 (GtkAccessibleRelationSet); + + return gtk_accessible_relation_set_init (set); +} + +GtkAccessibleRelationSet * +gtk_accessible_relation_set_ref (GtkAccessibleRelationSet *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return g_rc_box_acquire (self); +} + +static void +gtk_accessible_relation_set_free (gpointer data) +{ + GtkAccessibleRelationSet *self = data; + + for (int i = 0; i < LAST_RELATION; i++) + { + if (self->relation_values[i] != NULL) + gtk_accessible_value_unref (self->relation_values[i]); + } + + g_free (self->relation_values); + + _gtk_bitmask_free (self->relation_set); +} + +void +gtk_accessible_relation_set_unref (GtkAccessibleRelationSet *self) +{ + g_rc_box_release_full (self, gtk_accessible_relation_set_free); +} + +void +gtk_accessible_relation_set_add (GtkAccessibleRelationSet *self, + GtkAccessibleRelation relation, + GtkAccessibleValue *value) +{ + g_return_if_fail (relation >= GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT && + relation <= GTK_ACCESSIBLE_RELATION_SET_SIZE); + + if (gtk_accessible_relation_set_contains (self, relation)) + gtk_accessible_value_unref (self->relation_values[relation]); + else + self->relation_set = _gtk_bitmask_set (self->relation_set, relation, TRUE); + + self->relation_values[relation] = gtk_accessible_value_ref (value); +} + +void +gtk_accessible_relation_set_remove (GtkAccessibleRelationSet *self, + GtkAccessibleRelation relation) +{ + g_return_if_fail (relation >= GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT && + relation <= GTK_ACCESSIBLE_RELATION_SET_SIZE); + + if (gtk_accessible_relation_set_contains (self, relation)) + { + g_clear_pointer (&(self->relation_values[relation]), gtk_accessible_value_unref); + self->relation_set = _gtk_bitmask_set (self->relation_set, relation, FALSE); + } +} + +gboolean +gtk_accessible_relation_set_contains (GtkAccessibleRelationSet *self, + GtkAccessibleRelation relation) +{ + g_return_val_if_fail (relation >= GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT && + relation <= GTK_ACCESSIBLE_RELATION_SET_SIZE, + FALSE); + + return _gtk_bitmask_get (self->relation_set, relation); +} + +GtkAccessibleValue * +gtk_accessible_relation_set_get_value (GtkAccessibleRelationSet *self, + GtkAccessibleRelation relation) +{ + g_return_val_if_fail (relation >= GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT && + relation <= GTK_ACCESSIBLE_RELATION_SET_SIZE, + NULL); + + return self->relation_values[relation]; +} + +static const char *relation_names[] = { + [GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT] = "activedescendant", + [GTK_ACCESSIBLE_RELATION_COL_COUNT] = "colcount", + [GTK_ACCESSIBLE_RELATION_COL_INDEX] = "colindex", + [GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT] = "colindextext", + [GTK_ACCESSIBLE_RELATION_COL_SPAN] = "colspan", + [GTK_ACCESSIBLE_RELATION_CONTROLS] = "controls", + [GTK_ACCESSIBLE_RELATION_DESCRIBED_BY] = "describedby", + [GTK_ACCESSIBLE_RELATION_DETAILS] = "details", + [GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE] = "errormessage", + [GTK_ACCESSIBLE_RELATION_FLOW_TO] = "flowto", + [GTK_ACCESSIBLE_RELATION_LABELLED_BY] = "labelledby", + [GTK_ACCESSIBLE_RELATION_OWNS] = "owns", + [GTK_ACCESSIBLE_RELATION_POS_IN_SET] = "posinset", + [GTK_ACCESSIBLE_RELATION_ROW_COUNT] = "rowcount", + [GTK_ACCESSIBLE_RELATION_ROW_INDEX] = "rowindex", + [GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT] = "rowindextext", + [GTK_ACCESSIBLE_RELATION_ROW_SPAN] = "rowspan", + [GTK_ACCESSIBLE_RELATION_SET_SIZE] = "setsize", +}; + +/*< private > + * gtk_accessible_relation_set_print: + * @self: a #GtkAccessibleRelationSet + * @only_set: %TRUE if only the set relations should be printed + * @buffer: a #GString + * + * Prints the contents of the #GtkAccessibleRelationSet into @buffer. + */ +void +gtk_accessible_relation_set_print (GtkAccessibleRelationSet *self, + gboolean only_set, + GString *buffer) +{ + if (only_set && _gtk_bitmask_is_empty (self->relation_set)) + { + g_string_append (buffer, "{}"); + return; + } + + g_string_append (buffer, "{\n"); + + for (int i = 0; i < G_N_ELEMENTS (relation_names); i++) + { + if (only_set && !_gtk_bitmask_get (self->relation_set, i)) + continue; + + g_string_append (buffer, " "); + g_string_append (buffer, relation_names[i]); + g_string_append (buffer, ": "); + + gtk_accessible_value_print (self->relation_values[i], buffer); + + g_string_append (buffer, ",\n"); + } + + g_string_append (buffer, "}"); +} + +/*< private > + * gtk_accessible_relation_set_to_string: + * @self: a #GtkAccessibleRelationSet + * + * Prints the contents of a #GtkAccessibleRelationSet into a string. + * + * Returns: (transfer full): a newly allocated string with the contents + * of the #GtkAccessibleRelationSet + */ +char * +gtk_accessible_relation_set_to_string (GtkAccessibleRelationSet *self) +{ + GString *buf = g_string_new (NULL); + + gtk_accessible_relation_set_print (self, TRUE, buf); + + return g_string_free (buf, FALSE); +} diff --git a/gtk/gtkaccessiblerelationsetprivate.h b/gtk/gtkaccessiblerelationsetprivate.h new file mode 100644 index 0000000000..a2a33f9717 --- /dev/null +++ b/gtk/gtkaccessiblerelationsetprivate.h @@ -0,0 +1,49 @@ +/* gtkaccessiblerelationsetprivate.h: Accessible relations set + * + * Copyright 2020 GNOME Foundation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#pragma once + +#include "gtkaccessibleprivate.h" +#include "gtkaccessiblevalueprivate.h" + +G_BEGIN_DECLS + +typedef struct _GtkAccessibleRelationSet GtkAccessibleRelationSet; + +GtkAccessibleRelationSet * gtk_accessible_relation_set_new (void); +GtkAccessibleRelationSet * gtk_accessible_relation_set_ref (GtkAccessibleRelationSet *self); +void gtk_accessible_relation_set_unref (GtkAccessibleRelationSet *self); + +void gtk_accessible_relation_set_add (GtkAccessibleRelationSet *self, + GtkAccessibleRelation state, + GtkAccessibleValue *value); +void gtk_accessible_relation_set_remove (GtkAccessibleRelationSet *self, + GtkAccessibleRelation state); +gboolean gtk_accessible_relation_set_contains (GtkAccessibleRelationSet *self, + GtkAccessibleRelation state); +GtkAccessibleValue * gtk_accessible_relation_set_get_value (GtkAccessibleRelationSet *self, + GtkAccessibleRelation state); + +void gtk_accessible_relation_set_print (GtkAccessibleRelationSet *self, + gboolean only_set, + GString *string); +char * gtk_accessible_relation_set_to_string (GtkAccessibleRelationSet *self); + +G_END_DECLS diff --git a/gtk/gtkaccessiblevalue.c b/gtk/gtkaccessiblevalue.c index 58e3dd15d1..4ccd8a837d 100644 --- a/gtk/gtkaccessiblevalue.c +++ b/gtk/gtkaccessiblevalue.c @@ -665,6 +665,100 @@ static const GtkAccessibleCollect collect_props[] = { }, }; +/* § 6.6.4 Relationship Attributes */ +static const GtkAccessibleCollect collect_rels[] = { + [GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT] = { + .value = GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "activedescendant" + }, + [GTK_ACCESSIBLE_RELATION_COL_COUNT] = { + .value = GTK_ACCESSIBLE_RELATION_COL_COUNT, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "colcount" + }, + [GTK_ACCESSIBLE_RELATION_COL_INDEX] = { + .value = GTK_ACCESSIBLE_RELATION_COL_INDEX, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "colindex" + }, + [GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT] = { + .value = GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT, + .ctype = GTK_ACCESSIBLE_COLLECT_STRING, + .name = "colindextext" + }, + [GTK_ACCESSIBLE_RELATION_COL_SPAN] = { + .value = GTK_ACCESSIBLE_RELATION_COL_SPAN, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "colspan" + }, + [GTK_ACCESSIBLE_RELATION_CONTROLS] = { + .value = GTK_ACCESSIBLE_RELATION_CONTROLS, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "controls" + }, + [GTK_ACCESSIBLE_RELATION_DESCRIBED_BY] = { + .value = GTK_ACCESSIBLE_RELATION_DESCRIBED_BY, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "describedby" + }, + [GTK_ACCESSIBLE_RELATION_DETAILS] = { + .value = GTK_ACCESSIBLE_RELATION_DETAILS, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "details" + }, + [GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE] = { + .value = GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "errormessage" + }, + [GTK_ACCESSIBLE_RELATION_FLOW_TO] = { + .value = GTK_ACCESSIBLE_RELATION_FLOW_TO, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "flowto" + }, + [GTK_ACCESSIBLE_RELATION_LABELLED_BY] = { + .value = GTK_ACCESSIBLE_RELATION_LABELLED_BY, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "labelledby" + }, + [GTK_ACCESSIBLE_RELATION_OWNS] = { + .value = GTK_ACCESSIBLE_RELATION_OWNS, + .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE, + .name = "owns" + }, + [GTK_ACCESSIBLE_RELATION_POS_IN_SET] = { + .value = GTK_ACCESSIBLE_RELATION_POS_IN_SET, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "posinset" + }, + [GTK_ACCESSIBLE_RELATION_ROW_COUNT] = { + .value = GTK_ACCESSIBLE_RELATION_ROW_COUNT, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "rowcount" + }, + [GTK_ACCESSIBLE_RELATION_ROW_INDEX] = { + .value = GTK_ACCESSIBLE_RELATION_ROW_INDEX, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "rowindex" + }, + [GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT] = { + .value = GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT, + .ctype = GTK_ACCESSIBLE_COLLECT_STRING, + .name = "rowindextext" + }, + [GTK_ACCESSIBLE_RELATION_ROW_SPAN] = { + .value = GTK_ACCESSIBLE_RELATION_ROW_SPAN, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "rowspan" + }, + [GTK_ACCESSIBLE_RELATION_SET_SIZE] = { + .value = GTK_ACCESSIBLE_RELATION_SET_SIZE, + .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER, + .name = "posinset" + }, +}; + typedef GtkAccessibleValue * (* GtkAccessibleValueBooleanCtor) (gboolean value); typedef GtkAccessibleValue * (* GtkAccessibleValueIntCtor) (int value); typedef GtkAccessibleValue * (* GtkAccessibleValueTristateCtor) (int value); @@ -1117,4 +1211,93 @@ gtk_accessible_value_collect_for_property_value (GtkAccessibleProperty property return gtk_accessible_value_collect_value (cstate, value); } +/*< private > + * gtk_accessible_value_get_default_for_relation: + * @relation: a #GtkAccessibleRelation + * + * Retrieves the #GtkAccessibleValue that contains the default for the + * given @relation. + * + * Returns: (transfer full): the #GtkAccessibleValue + */ +GtkAccessibleValue * +gtk_accessible_value_get_default_for_relation (GtkAccessibleRelation relation) +{ + const GtkAccessibleCollect *cstate = &collect_rels[relation]; + + switch (cstate->value) + { + /* References */ + case GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT: + case GTK_ACCESSIBLE_RELATION_CONTROLS: + case GTK_ACCESSIBLE_RELATION_DESCRIBED_BY: + case GTK_ACCESSIBLE_RELATION_DETAILS: + case GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE: + case GTK_ACCESSIBLE_RELATION_FLOW_TO: + case GTK_ACCESSIBLE_RELATION_LABELLED_BY: + case GTK_ACCESSIBLE_RELATION_OWNS: + return NULL; + + /* Integers */ + case GTK_ACCESSIBLE_RELATION_COL_COUNT: + case GTK_ACCESSIBLE_RELATION_COL_INDEX: + case GTK_ACCESSIBLE_RELATION_COL_SPAN: + case GTK_ACCESSIBLE_RELATION_POS_IN_SET: + case GTK_ACCESSIBLE_RELATION_ROW_COUNT: + case GTK_ACCESSIBLE_RELATION_ROW_INDEX: + case GTK_ACCESSIBLE_RELATION_ROW_SPAN: + case GTK_ACCESSIBLE_RELATION_SET_SIZE: + return gtk_int_accessible_value_new (0); + + /* Strings */ + case GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT: + case GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT: + return gtk_string_accessible_value_new (""); + + default: + g_critical ("Unknown value for accessible property “%s”", cstate->name); + break; + } + + return NULL; +} + +/*< private > + * gtk_accessible_value_collect_for_relation: + * @relation: a #GtkAccessibleRelation + * @args: a `va_list` reference + * + * Collects and consumes the next item in the @args variadic arguments list, + * and returns a #GtkAccessibleValue for it. + * + * Returns: (transfer full): a #GtkAccessibleValue + */ +GtkAccessibleValue * +gtk_accessible_value_collect_for_relation (GtkAccessibleRelation relation, + va_list *args) +{ + const GtkAccessibleCollect *cstate = &collect_rels[relation]; + + return gtk_accessible_value_collect_valist (cstate, args); +} + +/*< private > + * gtk_accessible_value_collect_for_relation_value: + * @relation: a #GtkAccessibleRelation + * @value: a #GValue + * + * Retrieves the value stored inside @value and returns a #GtkAccessibleValue + * for the given @relation. + * + * Returns: (transfer full): a #GtkAccessibleValue + */ +GtkAccessibleValue * +gtk_accessible_value_collect_for_relation_value (GtkAccessibleRelation relation, + const GValue *value) +{ + const GtkAccessibleCollect *cstate = &collect_rels[relation]; + + return gtk_accessible_value_collect_value (cstate, value); +} + /* }}} */ diff --git a/gtk/gtkaccessiblevalueprivate.h b/gtk/gtkaccessiblevalueprivate.h index 9f80edac92..30648d1fb0 100644 --- a/gtk/gtkaccessiblevalueprivate.h +++ b/gtk/gtkaccessiblevalueprivate.h @@ -102,6 +102,12 @@ GtkAccessibleValue * gtk_accessible_value_collect_for_property (GtkAcce GtkAccessibleValue * gtk_accessible_value_collect_for_property_value (GtkAccessibleProperty property, const GValue *value); +GtkAccessibleValue * gtk_accessible_value_get_default_for_relation (GtkAccessibleRelation relation); +GtkAccessibleValue * gtk_accessible_value_collect_for_relation (GtkAccessibleRelation relation, + va_list *args); +GtkAccessibleValue * gtk_accessible_value_collect_for_relation_value (GtkAccessibleRelation relation, + const GValue *value); + /* Basic values */ GtkAccessibleValue * gtk_undefined_accessible_value_new (void); int gtk_undefined_accessible_value_get (const GtkAccessibleValue *value); diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c index 4fe0b8176f..6466678ad7 100644 --- a/gtk/gtkatcontext.c +++ b/gtk/gtkatcontext.c @@ -56,8 +56,9 @@ gtk_at_context_finalize (GObject *gobject) { GtkATContext *self = GTK_AT_CONTEXT (gobject); - gtk_accessible_state_set_unref (self->states); gtk_accessible_property_set_unref (self->properties); + gtk_accessible_relation_set_unref (self->relations); + gtk_accessible_state_set_unref (self->states); G_OBJECT_CLASS (gtk_at_context_parent_class)->finalize (gobject); } @@ -111,9 +112,11 @@ gtk_at_context_get_property (GObject *gobject, static void gtk_at_context_real_state_change (GtkATContext *self, GtkAccessibleStateChange changed_states, - GtkAccessiblePropertyChange changed_properies, + GtkAccessiblePropertyChange changed_properties, + GtkAccessibleRelationChange changed_relations, GtkAccessibleStateSet *states, - GtkAccessiblePropertySet *properties) + GtkAccessiblePropertySet *properties, + GtkAccessibleRelationSet *relations) { } @@ -168,8 +171,9 @@ gtk_at_context_init (GtkATContext *self) { self->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET; - self->states = gtk_accessible_state_set_new (); self->properties = gtk_accessible_property_set_new (); + self->relations = gtk_accessible_relation_set_new (); + self->states = gtk_accessible_state_set_new (); } /** @@ -269,6 +273,7 @@ gtk_at_context_update (GtkATContext *self) GtkAccessibleStateChange changed_states = 0; GtkAccessiblePropertyChange changed_properties = 0; + GtkAccessibleRelationChange changed_relations = 0; for (int i = 0; i < GTK_ACCESSIBLE_STATE_SELECTED; i++) { @@ -282,11 +287,19 @@ gtk_at_context_update (GtkATContext *self) changed_properties |= (1 << i); } + for (int i = 0; i < GTK_ACCESSIBLE_RELATION_SET_SIZE; i++) + { + if (gtk_accessible_relation_set_contains (self->relations, i)) + changed_relations |= (1 << i); + } + GTK_AT_CONTEXT_GET_CLASS (self)->state_change (self, changed_states, changed_properties, + changed_relations, self->states, - self->properties); + self->properties, + self->relations); } /*< private > @@ -340,3 +353,29 @@ gtk_at_context_set_accessible_property (GtkATContext *self, else gtk_accessible_property_set_remove (self->properties, property); } + +/*< private > + * gtk_at_context_set_accessible_relation: + * @self: a #GtkATContext + * @relation: a #GtkAccessibleRelation + * @value: (nullable): #GtkAccessibleValue + * + * Sets the @value for the given @relation of a #GtkATContext. + * + * If @value is %NULL, the relation is unset. + * + * This function will accumulate relation changes until gtk_at_context_update_state() + * is called. + */ +void +gtk_at_context_set_accessible_relation (GtkATContext *self, + GtkAccessibleRelation relation, + GtkAccessibleValue *value) +{ + g_return_if_fail (GTK_IS_AT_CONTEXT (self)); + + if (value != NULL) + gtk_accessible_relation_set_add (self->relations, relation, value); + else + gtk_accessible_relation_set_remove (self->relations, relation); +} diff --git a/gtk/gtkatcontextprivate.h b/gtk/gtkatcontextprivate.h index ec152a2060..ee7a6dea7c 100644 --- a/gtk/gtkatcontextprivate.h +++ b/gtk/gtkatcontextprivate.h @@ -22,22 +22,12 @@ #include "gtkatcontext.h" -#include "gtkaccessiblestatesetprivate.h" #include "gtkaccessiblepropertysetprivate.h" +#include "gtkaccessiblerelationsetprivate.h" +#include "gtkaccessiblestatesetprivate.h" G_BEGIN_DECLS -typedef enum { - GTK_ACCESSIBLE_STATE_CHANGE_BUSY = 1 << GTK_ACCESSIBLE_STATE_BUSY, - GTK_ACCESSIBLE_STATE_CHANGE_CHECKED = 1 << GTK_ACCESSIBLE_STATE_CHECKED, - GTK_ACCESSIBLE_STATE_CHANGE_DISABLED = 1 << GTK_ACCESSIBLE_STATE_DISABLED, - GTK_ACCESSIBLE_STATE_CHANGE_EXPANDED = 1 << GTK_ACCESSIBLE_STATE_EXPANDED, - GTK_ACCESSIBLE_STATE_CHANGE_HIDDEN = 1 << GTK_ACCESSIBLE_STATE_HIDDEN, - GTK_ACCESSIBLE_STATE_CHANGE_INVALID = 1 << GTK_ACCESSIBLE_STATE_INVALID, - GTK_ACCESSIBLE_STATE_CHANGE_PRESSED = 1 << GTK_ACCESSIBLE_STATE_PRESSED, - GTK_ACCESSIBLE_STATE_CHANGE_SELECTED = 1 << GTK_ACCESSIBLE_STATE_SELECTED -} GtkAccessibleStateChange; - typedef enum { GTK_ACCESSIBLE_PROPERTY_CHANGE_AUTOCOMPLETE = 1 << GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE, GTK_ACCESSIBLE_PROPERTY_CHANGE_DESCRIPTION = 1 << GTK_ACCESSIBLE_PROPERTY_DESCRIPTION, @@ -60,6 +50,38 @@ typedef enum { GTK_ACCESSIBLE_PROPERTY_CHANGE_VALUE_TEXT = 1 << GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT } GtkAccessiblePropertyChange; +typedef enum { + GTK_ACCESSIBLE_RELATION_CHANGE_ACTIVE_DESCENDANT = 1 << GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT, + GTK_ACCESSIBLE_RELATION_CHANGE_COL_COUNT = 1 << GTK_ACCESSIBLE_RELATION_COL_COUNT, + GTK_ACCESSIBLE_RELATION_CHANGE_COL_INDEX = 1 << GTK_ACCESSIBLE_RELATION_COL_INDEX, + GTK_ACCESSIBLE_RELATION_CHANGE_COL_INDEX_TEXT = 1 << GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT, + GTK_ACCESSIBLE_RELATION_CHANGE_COL_SPAN = 1 << GTK_ACCESSIBLE_RELATION_COL_SPAN, + GTK_ACCESSIBLE_RELATION_CHANGE_CONTROLS = 1 << GTK_ACCESSIBLE_RELATION_CONTROLS, + GTK_ACCESSIBLE_RELATION_CHANGE_DESCRIBED_BY = 1 << GTK_ACCESSIBLE_RELATION_DESCRIBED_BY, + GTK_ACCESSIBLE_RELATION_CHANGE_DETAILS = 1 << GTK_ACCESSIBLE_RELATION_DETAILS, + GTK_ACCESSIBLE_RELATION_CHANGE_ERROR_MESSAGE = 1 << GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE, + GTK_ACCESSIBLE_RELATION_CHANGE_FLOW_TO = 1 << GTK_ACCESSIBLE_RELATION_FLOW_TO, + GTK_ACCESSIBLE_RELATION_CHANGE_LABELLED_BY = 1 << GTK_ACCESSIBLE_RELATION_LABELLED_BY, + GTK_ACCESSIBLE_RELATION_CHANGE_OWNS = 1 << GTK_ACCESSIBLE_RELATION_OWNS, + GTK_ACCESSIBLE_RELATION_CHANGE_POS_IN_SET = 1 << GTK_ACCESSIBLE_RELATION_POS_IN_SET, + GTK_ACCESSIBLE_RELATION_CHANGE_ROW_COUNT = 1 << GTK_ACCESSIBLE_RELATION_ROW_COUNT, + GTK_ACCESSIBLE_RELATION_CHANGE_ROW_INDEX = 1 << GTK_ACCESSIBLE_RELATION_ROW_INDEX, + GTK_ACCESSIBLE_RELATION_CHANGE_ROW_INDEX_TEXT = 1 << GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT, + GTK_ACCESSIBLE_RELATION_CHANGE_ROW_SPAN = 1 << GTK_ACCESSIBLE_RELATION_ROW_SPAN, + GTK_ACCESSIBLE_RELATION_CHANGE_SET_SIZE = 1 << GTK_ACCESSIBLE_RELATION_SET_SIZE +} GtkAccessibleRelationChange; + +typedef enum { + GTK_ACCESSIBLE_STATE_CHANGE_BUSY = 1 << GTK_ACCESSIBLE_STATE_BUSY, + GTK_ACCESSIBLE_STATE_CHANGE_CHECKED = 1 << GTK_ACCESSIBLE_STATE_CHECKED, + GTK_ACCESSIBLE_STATE_CHANGE_DISABLED = 1 << GTK_ACCESSIBLE_STATE_DISABLED, + GTK_ACCESSIBLE_STATE_CHANGE_EXPANDED = 1 << GTK_ACCESSIBLE_STATE_EXPANDED, + GTK_ACCESSIBLE_STATE_CHANGE_HIDDEN = 1 << GTK_ACCESSIBLE_STATE_HIDDEN, + GTK_ACCESSIBLE_STATE_CHANGE_INVALID = 1 << GTK_ACCESSIBLE_STATE_INVALID, + GTK_ACCESSIBLE_STATE_CHANGE_PRESSED = 1 << GTK_ACCESSIBLE_STATE_PRESSED, + GTK_ACCESSIBLE_STATE_CHANGE_SELECTED = 1 << GTK_ACCESSIBLE_STATE_SELECTED +} GtkAccessibleStateChange; + struct _GtkATContext { GObject parent_instance; @@ -69,6 +91,7 @@ struct _GtkATContext GtkAccessibleStateSet *states; GtkAccessiblePropertySet *properties; + GtkAccessibleRelationSet *relations; }; struct _GtkATContextClass @@ -78,8 +101,10 @@ struct _GtkATContextClass void (* state_change) (GtkATContext *self, GtkAccessibleStateChange changed_states, GtkAccessiblePropertyChange changed_properties, + GtkAccessibleRelationChange changed_relations, GtkAccessibleStateSet *states, - GtkAccessiblePropertySet *properties); + GtkAccessiblePropertySet *properties, + GtkAccessibleRelationSet *relations); }; GtkATContext * gtk_at_context_create (GtkAccessibleRole accessible_role, @@ -93,5 +118,8 @@ void gtk_at_context_set_accessible_state (GtkATContext * void gtk_at_context_set_accessible_property (GtkATContext *self, GtkAccessibleProperty property, GtkAccessibleValue *value); +void gtk_at_context_set_accessible_relation (GtkATContext *self, + GtkAccessibleRelation property, + GtkAccessibleValue *value); G_END_DECLS diff --git a/gtk/gtktestatcontext.c b/gtk/gtktestatcontext.c index f89e354451..e9b7e8c0b4 100644 --- a/gtk/gtktestatcontext.c +++ b/gtk/gtktestatcontext.c @@ -36,24 +36,30 @@ static void gtk_test_at_context_state_change (GtkATContext *self, GtkAccessibleStateChange changed_states, GtkAccessiblePropertyChange changed_properties, + GtkAccessibleRelationChange changed_relations, GtkAccessibleStateSet *states, - GtkAccessiblePropertySet *properties) + GtkAccessiblePropertySet *properties, + GtkAccessibleRelationSet *relations) { GtkAccessible *accessible = gtk_at_context_get_accessible (self); GtkAccessibleRole role = gtk_at_context_get_accessible_role (self); char *states_str = gtk_accessible_state_set_to_string (states); char *properties_str = gtk_accessible_property_set_to_string (properties); + char *relations_str = gtk_accessible_relation_set_to_string (relations); g_print ("*** Accessible state changed for accessible “%s”, with role %d:\n" - "*** states = %s\n" - "*** properties = %s\n", + "*** states = %s\n" + "*** properties = %s\n" + "*** relations = %s\n", G_OBJECT_TYPE_NAME (accessible), role, states_str, - properties_str); + properties_str, + relations_str); g_free (states_str); g_free (properties_str); + g_free (relations_str); } static void diff --git a/gtk/meson.build b/gtk/meson.build index 432029a1ed..440be6f55c 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -17,6 +17,7 @@ gtk_private_sources = files([ 'tools/gdkpixbufutils.c', 'gsettings-mapping.c', 'gtkaccessiblepropertyset.c', + 'gtkaccessiblerelationset.c', 'gtkaccessiblestateset.c', 'gtkaccessiblevalue.c', 'gtkaccessiblevaluestatic.c',