From 3b8f99f555145fb8b1b64cd99c74e36263504e45 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 8 Jul 2020 16:34:32 +0100 Subject: [PATCH] Add GtkAccessibleValue All accessible properties and states may have one of the following types: - true/false - true/false/undefined - true/false/mixed/undefined - reference (to another UI element) - reference list - integer - number (real numerical value) - string - token (one of a limited set of allowed values) - token list See: https://www.w3.org/WAI/PF/aria/states_and_properties#propcharacteristic_value The GtkAccessibleValue is a simple reference counted type that can be "subclassed" to implement each value type. This initial commit adds GtkAccessibleValue and the basic subclasses for plain boolean, tristate (true/false/undefined), and token types, including statically allocated values that can be shared instead of allocated. --- gtk/gtkaccessiblevalue.c | 426 +++++++++++++++++++++++++++ gtk/gtkaccessiblevalueprivate.h | 135 +++++++++ gtk/gtkaccessiblevaluestatic.c | 495 ++++++++++++++++++++++++++++++++ gtk/gtkenums.h | 61 ++++ gtk/meson.build | 2 + 5 files changed, 1119 insertions(+) create mode 100644 gtk/gtkaccessiblevalue.c create mode 100644 gtk/gtkaccessiblevalueprivate.h create mode 100644 gtk/gtkaccessiblevaluestatic.c diff --git a/gtk/gtkaccessiblevalue.c b/gtk/gtkaccessiblevalue.c new file mode 100644 index 0000000000..617f512c92 --- /dev/null +++ b/gtk/gtkaccessiblevalue.c @@ -0,0 +1,426 @@ +/* gtkaccessiblevalue.c: Accessible value + * + * 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 . + */ + +/*< private > + * SECTION: gtkaccessiblevalue + * @Title: GtkAccessibleValue + * @Short_description: Container for accessible state and property values + * + * GtkAccessibleValue is a reference counted, generic container for values used + * to represent the state and properties of a #GtkAccessible implementation. + * + * There are two kinds of accessible value types: + * + * - hard coded, static values; GTK owns them, and their contents, and are + * guaranteed to exist for the duration of the application's life time + * - dynamic values; the accessible state owns the value and their contents, + * and they can be allocated and freed + * + * Typically, the former type of values is used for boolean, tristate, and + * token value; the latter is used for numbers, strings, and token lists. + * + * For more information on the types of values, see the [WAI-ARIA](https://www.w3.org/WAI/PF/aria/states_and_properties#propcharacteristic_value) + * reference. + */ + +#include "config.h" + +#include "gtkaccessiblevalueprivate.h" + +#include "gtkenums.h" + +G_DEFINE_QUARK (gtk-accessible-value-error-quark, gtk_accessible_value_error) + +G_DEFINE_BOXED_TYPE (GtkAccessibleValue, gtk_accessible_value, + gtk_accessible_value_ref, + gtk_accessible_value_unref) + +/*< private > + * gtk_accessible_value_alloc: + * @value_class: a #GtkAccessibleValueClass structure + * + * Allocates a new #GtkAccessibleValue subclass using @value_class as the + * type definition. + * + * Returns: (transfer full): the newly allocated #GtkAccessibleValue + */ +GtkAccessibleValue * +gtk_accessible_value_alloc (const GtkAccessibleValueClass *value_class) +{ + g_return_val_if_fail (value_class != NULL, NULL); + g_return_val_if_fail (value_class->instance_size >= sizeof (GtkAccessibleValue), NULL); + + GtkAccessibleValue *res = g_malloc0 (value_class->instance_size); + + /* We do not use grefcount, here, because we want to have statically + * allocated GtkAccessibleValue subclasses, and those cannot be initialized + * with g_ref_count_init() + */ + res->ref_count = 1; + res->value_class = value_class; + + if (res->value_class->init != NULL) + res->value_class->init (res); + + return res; +} + +/*< private > + * gtk_accessible_value_ref: + * @self: a #GtkAccessibleValue + * + * Acquires a reference on the given #GtkAccessibleValue. + * + * Returns: (transfer full): the value, with an additional reference + */ +GtkAccessibleValue * +gtk_accessible_value_ref (GtkAccessibleValue *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + self->ref_count += 1; + + return self; +} + +/*< private > + * gtk_accessible_value_unref: + * @self: (transfer full): a #GtkAccessibleValue + * + * Releases a reference on the given #GtkAccessibleValue. + */ +void +gtk_accessible_value_unref (GtkAccessibleValue *self) +{ + g_return_if_fail (self != NULL); + + self->ref_count -= 1; + if (self->ref_count == 0) + { + if (self->value_class->finalize != NULL) + self->value_class->finalize (self); + + g_free (self); + } +} + +/*< private > + * gtk_accessible_value_print: + * @self: a #GtkAccessibleValue + * @buffer: a #GString + * + * Prints the contents of a #GtkAccessibleValue into the given @buffer. + */ +void +gtk_accessible_value_print (const GtkAccessibleValue *self, + GString *buffer) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (buffer != NULL); + + if (self->value_class->print != NULL) + self->value_class->print (self, buffer); +} + +/*< private > + * gtk_accessible_value_to_string: + * @self: a #GtkAccessibleValue + * + * Fills a string with the contents of the given #GtkAccessibleValue. + * + * Returns: (transfer full): a string with the contents of the value + */ +char * +gtk_accessible_value_to_string (const GtkAccessibleValue *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + GString *buffer = g_string_new (NULL); + + gtk_accessible_value_print (self, buffer); + + return g_string_free (buffer, FALSE); +} + +/*< private > + * gtk_accessible_value_equal: + * @value_a: (nullable): the first #GtkAccessibleValue + * @value_b: (nullable): the second #GtkAccessibleValue + * + * Checks whether @value_a and @value_b are equal. + * + * This function is %NULL-safe. + * + * Returns: %TRUE if the given #GtkAccessibleValue instances are equal, + * and %FALSE otherwise + */ +gboolean +gtk_accessible_value_equal (const GtkAccessibleValue *value_a, + const GtkAccessibleValue *value_b) +{ + if (value_a == value_b) + return TRUE; + + if (value_a == NULL || value_b == NULL) + return FALSE; + + return value_a->value_class->equal (value_a, value_b); +} + +typedef enum { + GTK_ACCESSIBLE_COLLECT_INVALID, + GTK_ACCESSIBLE_COLLECT_BOOLEAN, + GTK_ACCESSIBLE_COLLECT_INTEGER, + GTK_ACCESSIBLE_COLLECT_TRISTATE, + GTK_ACCESSIBLE_COLLECT_ENUM +} GtkAccessibleCollectType; + +typedef GtkAccessibleValue *(* GtkAccessibleValueConstructor) (void); + +typedef struct { + GtkAccessibleState state; + GtkAccessibleCollectType ctype; + const char *state_name; + GCallback ctor; +} GtkAccessibleCollectState; + +static const GtkAccessibleCollectState collect_states[] = { +/* | State | Collected type | Name | Constructor | + * |-------------------------------|--------------------------------|-----------|----------------------------------| + */ + { GTK_ACCESSIBLE_STATE_BUSY, GTK_ACCESSIBLE_COLLECT_BOOLEAN, "busy", (GCallback) gtk_busy_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_CHECKED, GTK_ACCESSIBLE_COLLECT_ENUM, "checked", (GCallback) gtk_checked_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_DISABLED, GTK_ACCESSIBLE_COLLECT_BOOLEAN, "disabled", (GCallback) gtk_disabled_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_EXPANDED, GTK_ACCESSIBLE_COLLECT_TRISTATE, "expanded", (GCallback) gtk_expanded_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_GRABBED, GTK_ACCESSIBLE_COLLECT_TRISTATE, "grabbed", (GCallback) gtk_grabbed_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_HIDDEN, GTK_ACCESSIBLE_COLLECT_BOOLEAN, "hidden", (GCallback) gtk_hidden_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_INVALID, GTK_ACCESSIBLE_COLLECT_ENUM, "invalid", (GCallback) gtk_invalid_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_PRESSED, GTK_ACCESSIBLE_COLLECT_ENUM, "pressed", (GCallback) gtk_pressed_accessible_value_new }, + { GTK_ACCESSIBLE_STATE_SELECTED, GTK_ACCESSIBLE_COLLECT_TRISTATE, "selected", (GCallback) gtk_selected_accessible_value_new }, +}; + +typedef GtkAccessibleValue * (* GtkAccessibleValueBooleanCtor) (gboolean state); +typedef GtkAccessibleValue * (* GtkAccessibleValueIntCtor) (int state); +typedef GtkAccessibleValue * (* GtkAccessibleValueTristateCtor) (int state); +typedef GtkAccessibleValue * (* GtkAccessibleValueEnumCtor) (int state); + +/*< private > + * gtk_accessible_value_get_default_for_state: + * @state: a #GtkAccessibleState + * + * Retrieves the #GtkAccessibleValue that contains the default for the + * given @state. + * + * Returns: (transfer full): the #GtkAccessibleValue + */ +GtkAccessibleValue * +gtk_accessible_value_get_default_for_state (GtkAccessibleState state) +{ + g_assert (state != GTK_ACCESSIBLE_STATE_NONE); + + const GtkAccessibleCollectState *cstate = &collect_states[state]; + + switch (cstate->state) + { + case GTK_ACCESSIBLE_STATE_BUSY: + return gtk_busy_accessible_value_new (FALSE); + + case GTK_ACCESSIBLE_STATE_CHECKED: + return gtk_checked_accessible_value_new (GTK_ACCESSIBLE_CHECKED_UNDEFINED); + + case GTK_ACCESSIBLE_STATE_DISABLED: + return gtk_disabled_accessible_value_new (FALSE); + + case GTK_ACCESSIBLE_STATE_EXPANDED: + return gtk_expanded_accessible_value_new (GTK_ACCESSIBLE_STATE_UNDEFINED); + + case GTK_ACCESSIBLE_STATE_GRABBED: + return gtk_grabbed_accessible_value_new (GTK_ACCESSIBLE_STATE_UNDEFINED); + + case GTK_ACCESSIBLE_STATE_HIDDEN: + return gtk_hidden_accessible_value_new (FALSE); + + case GTK_ACCESSIBLE_STATE_INVALID: + return gtk_invalid_accessible_value_new (GTK_ACCESSIBLE_INVALID_FALSE); + + case GTK_ACCESSIBLE_STATE_PRESSED: + return gtk_pressed_accessible_value_new (GTK_ACCESSIBLE_PRESSED_UNDEFINED); + + case GTK_ACCESSIBLE_STATE_SELECTED: + return gtk_selected_accessible_value_new (GTK_ACCESSIBLE_STATE_UNDEFINED); + + case GTK_ACCESSIBLE_STATE_NONE: + default: + g_critical ("Unknown value for accessible state “%s”", cstate->state_name); + break; + } + + return NULL; +} + +/*< private > + * gtk_accessible_value_collect_for_state: + * @state: a #GtkAccessibleState + * @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_state (GtkAccessibleState state, + va_list *args) +{ + g_assert (state != GTK_ACCESSIBLE_STATE_NONE); + + const GtkAccessibleCollectState *cstate = &collect_states[state]; + + GtkAccessibleValue *res = NULL; + + switch (cstate->ctype) + { + case GTK_ACCESSIBLE_COLLECT_BOOLEAN: + { + GtkAccessibleValueBooleanCtor ctor = + (GtkAccessibleValueBooleanCtor) cstate->ctor; + + gboolean value = va_arg (*args, gboolean); + + res = (* ctor) (value); + } + break; + + case GTK_ACCESSIBLE_COLLECT_INTEGER: + { + GtkAccessibleValueIntCtor ctor = + (GtkAccessibleValueIntCtor) cstate->ctor; + + int value = va_arg (*args, int); + + res = (* ctor) (value); + } + break; + + case GTK_ACCESSIBLE_COLLECT_TRISTATE: + { + GtkAccessibleValueTristateCtor ctor = + (GtkAccessibleValueIntCtor) cstate->ctor; + + int value = va_arg (*args, int); + + res = (* ctor) (value); + } + break; + + case GTK_ACCESSIBLE_COLLECT_ENUM: + { + GtkAccessibleValueEnumCtor ctor = + (GtkAccessibleValueEnumCtor) cstate->ctor; + + int value = va_arg (*args, int); + + res = (* ctor) (value); + } + break; + + case GTK_ACCESSIBLE_COLLECT_INVALID: + default: + g_critical ("Unknown type for accessible state “%s”", cstate->state_name); + break; + } + + return res; +} + +/*< private > + * gtk_accessible_value_collect_for_state_value: + * @state: a #GtkAccessibleState + * @value: a #GValue + * + * Retrieves the value stored inside @value and returns a #GtkAccessibleValue + * for the given @state. + * + * Returns: (transfer full): a #GtkAccessibleValue + */ +GtkAccessibleValue * +gtk_accessible_value_collect_for_state_value (GtkAccessibleState state, + const GValue *value) +{ + g_assert (state != GTK_ACCESSIBLE_STATE_NONE); + + const GtkAccessibleCollectState *cstate = &collect_states[state]; + + GtkAccessibleValue *res = NULL; + + switch (cstate->ctype) + { + case GTK_ACCESSIBLE_COLLECT_BOOLEAN: + { + GtkAccessibleValueBooleanCtor ctor = + (GtkAccessibleValueBooleanCtor) cstate->ctor; + + gboolean value_ = g_value_get_boolean (value); + + res = (* ctor) (value_); + } + break; + + case GTK_ACCESSIBLE_COLLECT_INTEGER: + { + GtkAccessibleValueIntCtor ctor = + (GtkAccessibleValueIntCtor) cstate->ctor; + + int value_ = g_value_get_int (value); + + res = (* ctor) (value_); + } + break; + + case GTK_ACCESSIBLE_COLLECT_TRISTATE: + { + GtkAccessibleValueTristateCtor ctor = + (GtkAccessibleValueIntCtor) cstate->ctor; + + int value_ = g_value_get_int (value); + + res = (* ctor) (value_); + } + break; + + case GTK_ACCESSIBLE_COLLECT_ENUM: + { + GtkAccessibleValueEnumCtor ctor = + (GtkAccessibleValueEnumCtor) cstate->ctor; + + int value_ = g_value_get_enum (value); + + res = (* ctor) (value_); + } + break; + + case GTK_ACCESSIBLE_COLLECT_INVALID: + default: + g_critical ("Unknown value type for accessible state “%s”", cstate->state_name); + break; + } + + return res; +} diff --git a/gtk/gtkaccessiblevalueprivate.h b/gtk/gtkaccessiblevalueprivate.h new file mode 100644 index 0000000000..30454c4ed2 --- /dev/null +++ b/gtk/gtkaccessiblevalueprivate.h @@ -0,0 +1,135 @@ +/* gtkaccessiblevalueprivate.h: Accessible value + * + * 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 + +#include "gtkenums.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_ACCESSIBLE_VALUE (gtk_accessible_value_get_type()) + +#define GTK_ACCESSIBLE_VALUE_ERROR (gtk_accessible_value_error_quark()) + +typedef struct _GtkAccessibleValue GtkAccessibleValue; +typedef struct _GtkAccessibleValueClass GtkAccessibleValueClass; + +struct _GtkAccessibleValue +{ + const GtkAccessibleValueClass *value_class; + + int ref_count; +}; + +struct _GtkAccessibleValueClass +{ + const char *type_name; + gsize instance_size; + + void (* init) (GtkAccessibleValue *self); + void (* finalize) (GtkAccessibleValue *self); + void (* print) (const GtkAccessibleValue *self, + GString *string); + gboolean (* equal) (const GtkAccessibleValue *value_a, + const GtkAccessibleValue *value_b); +}; + +typedef enum { + GTK_ACCESSIBLE_VALUE_ERROR_READ_ONLY, + GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE, + GTK_ACCESSIBLE_VALUE_ERROR_INVALID_RANGE, + GTK_ACCESSIBLE_VALUE_ERROR_INVALID_TOKEN +} GtkAccessibleValueError; + +GType gtk_accessible_value_get_type (void) G_GNUC_CONST; +GQuark gtk_accessible_value_error_quark (void); + +GtkAccessibleValue * gtk_accessible_value_alloc (const GtkAccessibleValueClass *klass); +GtkAccessibleValue * gtk_accessible_value_ref (GtkAccessibleValue *self); +void gtk_accessible_value_unref (GtkAccessibleValue *self); +void gtk_accessible_value_print (const GtkAccessibleValue *self, + GString *buffer); +char * gtk_accessible_value_to_string (const GtkAccessibleValue *self); +gboolean gtk_accessible_value_equal (const GtkAccessibleValue *value_a, + const GtkAccessibleValue *value_b); + +GtkAccessibleValue * gtk_accessible_value_get_default_for_state (GtkAccessibleState state); + +GtkAccessibleValue * gtk_accessible_value_collect_for_state (GtkAccessibleState state, + va_list *args); +GtkAccessibleValue * gtk_accessible_value_collect_for_state_value (GtkAccessibleState state, + const GValue *value); + +typedef enum { /*< prefix=GTK_ACCESSIBLE_CHECKED >*/ + GTK_ACCESSIBLE_CHECKED_FALSE = 0, + GTK_ACCESSIBLE_CHECKED_TRUE = 1, + GTK_ACCESSIBLE_CHECKED_UNDEFINED = -1, + GTK_ACCESSIBLE_CHECKED_MIXED = -2 +} GtkAccessibleCheckedState; + +typedef enum { /*< prefix=GTK_ACCESSIBLE_PRESSED >*/ + GTK_ACCESSIBLE_PRESSED_FALSE = 0, + GTK_ACCESSIBLE_PRESSED_TRUE = 1, + GTK_ACCESSIBLE_PRESSED_UNDEFINED = -1, + GTK_ACCESSIBLE_PRESSED_MIXED = -2 +} GtkAccessiblePressedState; + +typedef enum { /*< prefix=GTK_ACCESSIBLE_INVALID >*/ + GTK_ACCESSIBLE_INVALID_FALSE, + GTK_ACCESSIBLE_INVALID_TRUE, + GTK_ACCESSIBLE_INVALID_GRAMMAR, + GTK_ACCESSIBLE_INVALID_SPELLING, +} GtkAccessibleInvalidState; + +#define GTK_ACCESSIBLE_STATE_UNDEFINED (-1) + +/* Boolean states */ +GtkAccessibleValue * gtk_busy_accessible_value_new (gboolean state); +gboolean gtk_busy_accessible_value_get (const GtkAccessibleValue *value); + +GtkAccessibleValue * gtk_disabled_accessible_value_new (gboolean state); +gboolean gtk_disabled_accessible_value_get (const GtkAccessibleValue *value); + +GtkAccessibleValue * gtk_hidden_accessible_value_new (gboolean state); +gboolean gtk_hidden_accessible_value_get (const GtkAccessibleValue *value); + +/* Tri-state states */ +GtkAccessibleValue * gtk_expanded_accessible_value_new (int state); +int gtk_expanded_accessible_value_get (const GtkAccessibleValue *value); + +GtkAccessibleValue * gtk_grabbed_accessible_value_new (int state); +int gtk_grabbed_accessible_value_get (const GtkAccessibleValue *value); + +GtkAccessibleValue * gtk_selected_accessible_value_new (int state); +int gtk_selected_accessible_value_get (const GtkAccessibleValue *value); + +/* Token states */ +GtkAccessibleValue * gtk_pressed_accessible_value_new (GtkAccessiblePressedState state); +GtkAccessiblePressedState gtk_pressed_accessible_value_get (const GtkAccessibleValue *value); + +GtkAccessibleValue * gtk_checked_accessible_value_new (GtkAccessibleCheckedState state); +GtkAccessibleCheckedState gtk_checked_accessible_value_get (const GtkAccessibleValue *value); + +GtkAccessibleValue * gtk_invalid_accessible_value_new (GtkAccessibleInvalidState state); +GtkAccessibleInvalidState gtk_invalid_accessible_value_get (const GtkAccessibleValue *value); + +G_END_DECLS diff --git a/gtk/gtkaccessiblevaluestatic.c b/gtk/gtkaccessiblevaluestatic.c new file mode 100644 index 0000000000..c41f92cac7 --- /dev/null +++ b/gtk/gtkaccessiblevaluestatic.c @@ -0,0 +1,495 @@ +/* gtkaccessiblevaluestatic.c: GtkAccessibleValue static implementations + * + * 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 "gtkaccessiblevalueprivate.h" + +/* {{{ Boolean values */ + +typedef struct +{ + GtkAccessibleValue parent; + + gboolean value; +} GtkBooleanAccessibleValue; + +static gboolean +gtk_boolean_accessible_value_equal (const GtkAccessibleValue *value_a, + const GtkAccessibleValue *value_b) +{ + const GtkBooleanAccessibleValue *bool_a = (GtkBooleanAccessibleValue *) value_a; + const GtkBooleanAccessibleValue *bool_b = (GtkBooleanAccessibleValue *) value_b; + + return bool_a->value == bool_b->value; +} + +static void +gtk_boolean_accessible_value_print (const GtkAccessibleValue *value, + GString *buffer) +{ + const GtkBooleanAccessibleValue *self = (GtkBooleanAccessibleValue *) value; + + g_string_append_printf (buffer, "%s", self->value ? "true" : "false"); +} + +static const GtkAccessibleValueClass GTK_BUSY_ACCESSIBLE_VALUE = { + .type_name = "GtkBusyAccessibleValue", + .instance_size = sizeof (GtkBooleanAccessibleValue), + .equal = gtk_boolean_accessible_value_equal, + .print = gtk_boolean_accessible_value_print, +}; + +static GtkBooleanAccessibleValue busy_values[] = { + { { >K_BUSY_ACCESSIBLE_VALUE, 1 }, FALSE }, + { { >K_BUSY_ACCESSIBLE_VALUE, 1 }, TRUE }, +}; + +GtkAccessibleValue * +gtk_busy_accessible_value_new (gboolean state) +{ + if (state) + return gtk_accessible_value_ref ((GtkAccessibleValue *) &busy_values[1]); + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &busy_values[0]); +} + +gboolean +gtk_busy_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkBooleanAccessibleValue *self = (GtkBooleanAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (value->value_class == >K_BUSY_ACCESSIBLE_VALUE, FALSE); + + return self->value; +} + +static const GtkAccessibleValueClass GTK_DISABLED_ACCESSIBLE_VALUE = { + .type_name = "GtkDisabledAccessibleValue", + .instance_size = sizeof (GtkBooleanAccessibleValue), + .equal = gtk_boolean_accessible_value_equal, + .print = gtk_boolean_accessible_value_print, +}; + +static GtkBooleanAccessibleValue disabled_values[] = { + { { >K_DISABLED_ACCESSIBLE_VALUE, 1 }, FALSE }, + { { >K_DISABLED_ACCESSIBLE_VALUE, 1 }, TRUE }, +}; + +GtkAccessibleValue * +gtk_disabled_accessible_value_new (gboolean state) +{ + if (state) + return gtk_accessible_value_ref ((GtkAccessibleValue *) &disabled_values[1]); + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &disabled_values[0]); +} + +gboolean +gtk_disabled_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkBooleanAccessibleValue *self = (GtkBooleanAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (value->value_class == >K_DISABLED_ACCESSIBLE_VALUE, FALSE); + + return self->value; +} + +static const GtkAccessibleValueClass GTK_HIDDEN_ACCESSIBLE_VALUE = { + .type_name = "GtkHiddenAccessibleValue", + .instance_size = sizeof (GtkBooleanAccessibleValue), + .equal = gtk_boolean_accessible_value_equal, + .print = gtk_boolean_accessible_value_print, +}; + +static GtkBooleanAccessibleValue hidden_values[] = { + { { >K_HIDDEN_ACCESSIBLE_VALUE, 1 }, FALSE }, + { { >K_HIDDEN_ACCESSIBLE_VALUE, 1 }, TRUE }, +}; + +GtkAccessibleValue * +gtk_hidden_accessible_value_new (gboolean state) +{ + if (state) + return gtk_accessible_value_ref ((GtkAccessibleValue *) &hidden_values[1]); + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &hidden_values[0]); +} + +gboolean +gtk_hidden_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkBooleanAccessibleValue *self = (GtkBooleanAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (value->value_class == >K_HIDDEN_ACCESSIBLE_VALUE, FALSE); + + return self->value; +} + +/* }}} */ + +/* {{{ Tri-state values */ + +typedef struct { + GtkAccessibleValue parent; + + int value; +} GtkTristateAccessibleValue; + +static gboolean +gtk_tristate_accessible_value_equal (const GtkAccessibleValue *value_a, + const GtkAccessibleValue *value_b) +{ + const GtkTristateAccessibleValue *tri_a = (GtkTristateAccessibleValue *) value_a; + const GtkTristateAccessibleValue *tri_b = (GtkTristateAccessibleValue *) value_b; + + return tri_a->value == tri_b->value; +} + +static void +gtk_tristate_accessible_value_print (const GtkAccessibleValue *value, + GString *buffer) +{ + const GtkTristateAccessibleValue *self = (GtkTristateAccessibleValue *) value; + + switch (self->value) + { + case 0: + g_string_append (buffer, "false"); + break; + + case 1: + g_string_append (buffer, "true"); + break; + + case -1: + g_string_append (buffer, "undefined"); + break; + + default: + g_assert_not_reached (); + break; + } +} + +static const GtkAccessibleValueClass GTK_EXPANDED_ACCESSIBLE_VALUE = { + .type_name = "GtkExpandedAccessibleValue", + .instance_size = sizeof (GtkTristateAccessibleValue), + .equal = gtk_tristate_accessible_value_equal, + .print = gtk_tristate_accessible_value_print, +}; + +static GtkTristateAccessibleValue expanded_values[] = { + { { >K_EXPANDED_ACCESSIBLE_VALUE, 1 }, -1 }, + { { >K_EXPANDED_ACCESSIBLE_VALUE, 1 }, 0 }, + { { >K_EXPANDED_ACCESSIBLE_VALUE, 1 }, 1 }, +}; + +GtkAccessibleValue * +gtk_expanded_accessible_value_new (int state) +{ + int index_; + + if (state < 0) + index_ = 0; + else if (state == 0) + index_ = 1; + else + index_ = 2; + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &expanded_values[index_]); +} + +int +gtk_expanded_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkTristateAccessibleValue *self = (GtkTristateAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, GTK_ACCESSIBLE_STATE_UNDEFINED); + g_return_val_if_fail (value->value_class == >K_EXPANDED_ACCESSIBLE_VALUE, + GTK_ACCESSIBLE_STATE_UNDEFINED); + + return self->value; +} + +static const GtkAccessibleValueClass GTK_GRABBED_ACCESSIBLE_VALUE = { + .type_name = "GtkGrabbedAccessibleValue", + .instance_size = sizeof (GtkTristateAccessibleValue), + .equal = gtk_tristate_accessible_value_equal, + .print = gtk_tristate_accessible_value_print, +}; + +static GtkTristateAccessibleValue grabbed_values[] = { + { { >K_GRABBED_ACCESSIBLE_VALUE, 1 }, -1 }, + { { >K_GRABBED_ACCESSIBLE_VALUE, 1 }, 0 }, + { { >K_GRABBED_ACCESSIBLE_VALUE, 1 }, 1 }, +}; + +GtkAccessibleValue * +gtk_grabbed_accessible_value_new (int state) +{ + int index_; + + if (state < 0) + index_ = 0; + else if (state == 0) + index_ = 1; + else + index_ = 2; + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &grabbed_values[index_]); +} + +int +gtk_grabbed_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkTristateAccessibleValue *self = (GtkTristateAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, GTK_ACCESSIBLE_STATE_UNDEFINED); + g_return_val_if_fail (value->value_class == >K_GRABBED_ACCESSIBLE_VALUE, + GTK_ACCESSIBLE_STATE_UNDEFINED); + + return self->value; +} + +static const GtkAccessibleValueClass GTK_SELECTED_ACCESSIBLE_VALUE = { + .type_name = "GtkSelectedAccessibleValue", + .instance_size = sizeof (GtkTristateAccessibleValue), + .equal = gtk_tristate_accessible_value_equal, + .print = gtk_tristate_accessible_value_print, +}; + +static GtkTristateAccessibleValue selected_values[] = { + { { >K_SELECTED_ACCESSIBLE_VALUE, 1 }, -1 }, + { { >K_SELECTED_ACCESSIBLE_VALUE, 1 }, 0 }, + { { >K_SELECTED_ACCESSIBLE_VALUE, 1 }, 1 }, +}; + +GtkAccessibleValue * +gtk_selected_accessible_value_new (int state) +{ + int index_; + + if (state < 0) + index_ = 0; + else if (state == 0) + index_ = 1; + else + index_ = 2; + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &selected_values[index_]); +} + +int +gtk_selected_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkTristateAccessibleValue *self = (GtkTristateAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, GTK_ACCESSIBLE_STATE_UNDEFINED); + g_return_val_if_fail (value->value_class == >K_SELECTED_ACCESSIBLE_VALUE, + GTK_ACCESSIBLE_STATE_UNDEFINED); + + return self->value; +} + +/* }}} */ + +/* {{{ Enumeration values */ + +typedef struct { + GtkAccessibleValue parent; + + int value; + const char *token; +} GtkEnumAccessibleValue; + +static gboolean +gtk_enum_accessible_value_equal (const GtkAccessibleValue *value_a, + const GtkAccessibleValue *value_b) +{ + const GtkEnumAccessibleValue *enum_a = (GtkEnumAccessibleValue *) value_a; + const GtkEnumAccessibleValue *enum_b = (GtkEnumAccessibleValue *) value_b; + + return enum_a->value == enum_b->value; +} + +static void +gtk_enum_accessible_value_print (const GtkAccessibleValue *value, + GString *buffer) +{ + const GtkEnumAccessibleValue *self = (GtkEnumAccessibleValue *) value; + + g_string_append (buffer, self->token); +} + +static const GtkAccessibleValueClass GTK_CHECKED_ACCESSIBLE_VALUE = { + .type_name = "GtkCheckedAccessibleValue", + .instance_size = sizeof (GtkEnumAccessibleValue), + .equal = gtk_enum_accessible_value_equal, + .print = gtk_enum_accessible_value_print, +}; + +static GtkEnumAccessibleValue checked_values[] = { + { { >K_CHECKED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_CHECKED_FALSE, "false" }, + { { >K_CHECKED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_CHECKED_TRUE, "true" }, + { { >K_CHECKED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_PRESSED_UNDEFINED, "undefined" }, + { { >K_CHECKED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_CHECKED_MIXED, "mixed" }, +}; + +GtkAccessibleValue * +gtk_checked_accessible_value_new (GtkAccessibleCheckedState state) +{ + int index_; + + switch (state) + { + case GTK_ACCESSIBLE_CHECKED_FALSE: + index_ = 0; + break; + + case GTK_ACCESSIBLE_CHECKED_TRUE: + index_ = 1; + break; + + case GTK_ACCESSIBLE_CHECKED_UNDEFINED: + index_ = 2; + break; + + case GTK_ACCESSIBLE_CHECKED_MIXED: + index_ = 3; + break; + + default: + g_assert_not_reached (); + return NULL; + } + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &checked_values[index_]); +} + +GtkAccessibleCheckedState +gtk_checked_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkEnumAccessibleValue *self = (GtkEnumAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, GTK_ACCESSIBLE_CHECKED_UNDEFINED); + g_return_val_if_fail (value->value_class == >K_CHECKED_ACCESSIBLE_VALUE, + GTK_ACCESSIBLE_CHECKED_UNDEFINED); + + return self->value; +} + +static const GtkAccessibleValueClass GTK_PRESSED_ACCESSIBLE_VALUE = { + .type_name = "GtkPressedAccessibleValue", + .instance_size = sizeof (GtkEnumAccessibleValue), + .equal = gtk_enum_accessible_value_equal, + .print = gtk_enum_accessible_value_print, +}; + +static GtkEnumAccessibleValue pressed_values[] = { + { { >K_PRESSED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_PRESSED_FALSE, "false" }, + { { >K_PRESSED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_PRESSED_TRUE, "true" }, + { { >K_PRESSED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_PRESSED_UNDEFINED, "undefined" }, + { { >K_PRESSED_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_PRESSED_MIXED, "mixed" }, +}; + +GtkAccessibleValue * +gtk_pressed_accessible_value_new (GtkAccessiblePressedState state) +{ + int index_; + + switch (state) + { + case GTK_ACCESSIBLE_PRESSED_FALSE: + index_ = 0; + break; + + case GTK_ACCESSIBLE_PRESSED_TRUE: + index_ = 1; + break; + + case GTK_ACCESSIBLE_PRESSED_UNDEFINED: + index_ = 2; + break; + + case GTK_ACCESSIBLE_PRESSED_MIXED: + index_ = 3; + break; + + default: + g_assert_not_reached (); + return NULL; + } + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &pressed_values[index_]); +} + +GtkAccessiblePressedState +gtk_pressed_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkEnumAccessibleValue *self = (GtkEnumAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, GTK_ACCESSIBLE_PRESSED_UNDEFINED); + g_return_val_if_fail (value->value_class == >K_PRESSED_ACCESSIBLE_VALUE, + GTK_ACCESSIBLE_PRESSED_UNDEFINED); + + return self->value; +} + +static const GtkAccessibleValueClass GTK_INVALID_ACCESSIBLE_VALUE = { + .type_name = "GtkInvalidAccessibleValue", + .instance_size = sizeof (GtkEnumAccessibleValue), + .equal = gtk_enum_accessible_value_equal, + .print = gtk_enum_accessible_value_print, +}; + +static GtkEnumAccessibleValue invalid_values[] = { + { { >K_INVALID_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_INVALID_FALSE, "false" }, + { { >K_INVALID_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_INVALID_TRUE, "true" }, + { { >K_INVALID_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_INVALID_GRAMMAR, "grammar" }, + { { >K_INVALID_ACCESSIBLE_VALUE, 1 }, GTK_ACCESSIBLE_INVALID_SPELLING, "spelling" }, +}; + +GtkAccessibleValue * +gtk_invalid_accessible_value_new (GtkAccessibleInvalidState state) +{ + g_return_val_if_fail (state >= GTK_ACCESSIBLE_INVALID_FALSE && + state <= GTK_ACCESSIBLE_INVALID_SPELLING, + NULL); + + return gtk_accessible_value_ref ((GtkAccessibleValue *) &invalid_values[state]); +} + +GtkAccessibleInvalidState +gtk_invalid_accessible_value_get (const GtkAccessibleValue *value) +{ + GtkEnumAccessibleValue *self = (GtkEnumAccessibleValue *) value; + + g_return_val_if_fail (value != NULL, GTK_ACCESSIBLE_INVALID_FALSE); + g_return_val_if_fail (value->value_class == >K_INVALID_ACCESSIBLE_VALUE, + GTK_ACCESSIBLE_INVALID_FALSE); + + return self->value; +} + +/* }}} */ diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index c406fa0e48..2fc8b4cdea 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -1300,4 +1300,65 @@ typedef enum { GTK_ACCESSIBLE_ROLE_WINDOW } GtkAccessibleRole; +/** + * GtkAccessibleState: + * @GTK_ACCESSIBLE_STATE_NONE: An invalid state, used as a sentinel value + * @GTK_ACCESSIBLE_STATE_BUSY: A “busy” state + * @GTK_ACCESSIBLE_STATE_CHECKED: A “checked” state; corresponds to the + * #GtkToggleButton:active property on #GtkToggleButton + * @GTK_ACCESSIBLE_STATE_DISABLED: A “disabled” state; corresponds to the + * #GtkWidget:sensitive property on #GtkWidget + * @GTK_ACCESSIBLE_STATE_EXPANDED: An “expanded” state; corresponds to the + * #GtkExpander:expanded property on #GtkExpander + * @GTK_ACCESSIBLE_STATE_GRABBED: A “grabbed” state; set when a widget is + * being grabbed in a drag and drop operation + * @GTK_ACCESSIBLE_STATE_HIDDEN: A “hidden” state; corresponds to the + * #GtkWidget:visible property on #GtkWidget + * @GTK_ACCESSIBLE_STATE_INVALID: An “invalid” state; set when a widget + * is showing an error + * @GTK_ACCESSIBLE_STATE_PRESSED: A “pressed” state; set when a widget + * is being activated by a pointer + * @GTK_ACCESSIBLE_STATE_SELECTED: A “selected” state; set when a widget + * is selected + * + * The possible accessible state of a #GtkAccessible. + */ +typedef enum { + GTK_ACCESSIBLE_STATE_NONE = -1, + GTK_ACCESSIBLE_STATE_BUSY = 0, + GTK_ACCESSIBLE_STATE_CHECKED, + GTK_ACCESSIBLE_STATE_DISABLED, + GTK_ACCESSIBLE_STATE_EXPANDED, + GTK_ACCESSIBLE_STATE_GRABBED, + GTK_ACCESSIBLE_STATE_HIDDEN, + GTK_ACCESSIBLE_STATE_INVALID, + GTK_ACCESSIBLE_STATE_PRESSED, + GTK_ACCESSIBLE_STATE_SELECTED +} GtkAccessibleState; + +typedef enum { + GTK_ACCESSIBLE_PROPERTY_ACTIVE_DESCENDANT, + GTK_ACCESSIBLE_PROPERTY_CONTROLS, + GTK_ACCESSIBLE_PROPERTY_DESCRIBED_BY, + GTK_ACCESSIBLE_PROPERTY_FLOW_TO, + GTK_ACCESSIBLE_PROPERTY_HAS_POPUP, + GTK_ACCESSIBLE_PROPERTY_LABEL, + GTK_ACCESSIBLE_PROPERTY_LABELLED_BY, + GTK_ACCESSIBLE_PROPERTY_LEVEL, + GTK_ACCESSIBLE_PROPERTY_MULTI_LINE, + GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE, + GTK_ACCESSIBLE_PROPERTY_ORIENTATION, + GTK_ACCESSIBLE_PROPERTY_OWNS, + GTK_ACCESSIBLE_PROPERTY_POS_IN_SET, + GTK_ACCESSIBLE_PROPERTY_READ_ONLY, + GTK_ACCESSIBLE_PROPERTY_RELEVANT, + GTK_ACCESSIBLE_PROPERTY_REQUIRED, + GTK_ACCESSIBLE_PROPERTY_SET_SIZE, + GTK_ACCESSIBLE_PROPERTY_SORT, + GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, + GTK_ACCESSIBLE_PROPERTY_VALUE_MIN, + GTK_ACCESSIBLE_PROPERTY_VALUE_NOW, + GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT +} GtkAccessibleProperty; + #endif /* __GTK_ENUMS_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 9fadea55e0..5ac04668cb 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -16,6 +16,8 @@ gtk_private_sources = files([ 'fnmatch.c', 'tools/gdkpixbufutils.c', 'gsettings-mapping.c', + 'gtkaccessiblevalue.c', + 'gtkaccessiblevaluestatic.c', 'gtkactionhelper.c', 'gtkactionmuxer.c', 'gtkactionobservable.c',