Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gtkaccessiblevalue.c

  Sprache: C
 

/* 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 <http://www.gnu.org/licenses/>.
 */


/*< private >
 * GtkAccessibleValue:
 *
 * 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 "gtkaccessible.h"
#include "gtkbuilderprivate.h"
#include "gtkenums.h"
#include "gtktypebuiltins.h"

#include <math.h>
#include <float.h>
#include <errno.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;

  if (value_a->value_class != value_b->value_class)
    return FALSE;

  if (value_a->value_class->equal == NULL)
    return FALSE;

  return value_a->value_class->equal (value_a, value_b);
}

/* {{{ Basic allocated types */

typedef struct {
  GtkAccessibleValue parent;

  int value;
} GtkIntAccessibleValue;

static gboolean
gtk_int_accessible_value_equal (const GtkAccessibleValue *value_a,
                                const GtkAccessibleValue *value_b)
{
  const GtkIntAccessibleValue *self_a = (GtkIntAccessibleValue *) value_a;
  const GtkIntAccessibleValue *self_b = (GtkIntAccessibleValue *) value_b;

  return self_a->value == self_b->value;
}

static void
gtk_int_accessible_value_print (const GtkAccessibleValue *value,
                                GString                  *buffer)
{
  const GtkIntAccessibleValue *self = (GtkIntAccessibleValue *) value;

  g_string_append_printf (buffer, "%d", self->value);
}

static const GtkAccessibleValueClass GTK_INT_ACCESSIBLE_VALUE = {
  .type = GTK_ACCESSIBLE_VALUE_TYPE_INTEGER,
  .type_name = "GtkIntAccessibleValue",
  .instance_size = sizeof (GtkIntAccessibleValue),
  .equal = gtk_int_accessible_value_equal,
  .print = gtk_int_accessible_value_print,
};

GtkAccessibleValue *
gtk_int_accessible_value_new (int value)
{
  GtkAccessibleValue *res = gtk_accessible_value_alloc (>K_INT_ACCESSIBLE_VALUE);

  /* XXX: Possible optimization: statically allocate the first N values
   *      and hand out references to them, instead of dynamically
   *      allocating a new GtkAccessibleValue instance. Needs some profiling
   *      to figure out the common integer values used by large applications
   */

  GtkIntAccessibleValue *self = (GtkIntAccessibleValue *) res;
  self->value = value;

  return res;
}

int
gtk_int_accessible_value_get (const GtkAccessibleValue *value)
{
  GtkIntAccessibleValue *self = (GtkIntAccessibleValue *) value;

  g_return_val_if_fail (value != NULL, 0);
  g_return_val_if_fail (value->value_class == >K_INT_ACCESSIBLE_VALUE, 0);

  return self->value;
}

typedef struct {
  GtkAccessibleValue parent;

  double value;
} GtkNumberAccessibleValue;

static gboolean
gtk_number_accessible_value_equal (const GtkAccessibleValue *value_a,
                                   const GtkAccessibleValue *value_b)
{
  const GtkNumberAccessibleValue *self_a = (GtkNumberAccessibleValue *) value_a;
  const GtkNumberAccessibleValue *self_b = (GtkNumberAccessibleValue *) value_b;

  return G_APPROX_VALUE (self_a->value, self_b->value, 0.001);
}

static void
gtk_number_accessible_value_print (const GtkAccessibleValue *value,
                                   GString                  *buffer)
{
  const GtkNumberAccessibleValue *self = (GtkNumberAccessibleValue *) value;

  g_string_append_printf (buffer, "%g", self->value);
}

static const GtkAccessibleValueClass GTK_NUMBER_ACCESSIBLE_VALUE = {
  .type = GTK_ACCESSIBLE_VALUE_TYPE_NUMBER,
  .type_name = "GtkNumberAccessibleValue",
  .instance_size = sizeof (GtkNumberAccessibleValue),
  .equal = gtk_number_accessible_value_equal,
  .print = gtk_number_accessible_value_print,
};

GtkAccessibleValue *
gtk_number_accessible_value_new (double value)
{
  GtkAccessibleValue *res = gtk_accessible_value_alloc (>K_NUMBER_ACCESSIBLE_VALUE);

  GtkNumberAccessibleValue *self = (GtkNumberAccessibleValue *) res;
  self->value = value;

  return res;
}

double
gtk_number_accessible_value_get (const GtkAccessibleValue *value)
{
  GtkNumberAccessibleValue *self = (GtkNumberAccessibleValue *) value;

  g_return_val_if_fail (value != NULL, 0);
  g_return_val_if_fail (value->value_class == >K_NUMBER_ACCESSIBLE_VALUE, 0);

  return self->value;
}

typedef struct {
  GtkAccessibleValue parent;

  char *value;
  gsize length;
} GtkStringAccessibleValue;

static void
gtk_string_accessible_value_finalize (GtkAccessibleValue *value)
{
  GtkStringAccessibleValue *self = (GtkStringAccessibleValue *) value;

  g_free (self->value);
}

static gboolean
gtk_string_accessible_value_equal (const GtkAccessibleValue *value_a,
                                   const GtkAccessibleValue *value_b)
{
  const GtkStringAccessibleValue *self_a = (GtkStringAccessibleValue *) value_a;
  const GtkStringAccessibleValue *self_b = (GtkStringAccessibleValue *) value_b;

  if (self_a->length != self_b->length)
    return FALSE;

  return g_strcmp0 (self_a->value, self_b->value) == 0;
}

static void
gtk_string_accessible_value_print (const GtkAccessibleValue *value,
                                   GString                  *buffer)
{
  const GtkStringAccessibleValue *self = (GtkStringAccessibleValue *) value;

  g_string_append (buffer, self->value);
}

static const GtkAccessibleValueClass GTK_STRING_ACCESSIBLE_VALUE = {
  .type = GTK_ACCESSIBLE_VALUE_TYPE_STRING,
  .type_name = "GtkStringAccessibleValue",
  .instance_size = sizeof (GtkStringAccessibleValue),
  .finalize = gtk_string_accessible_value_finalize,
  .equal = gtk_string_accessible_value_equal,
  .print = gtk_string_accessible_value_print,
};

GtkAccessibleValue *
gtk_string_accessible_value_new (const char *str)
{
  GtkAccessibleValue *res = gtk_accessible_value_alloc (>K_STRING_ACCESSIBLE_VALUE);

  GtkStringAccessibleValue *self = (GtkStringAccessibleValue *) res;

  self->value = g_strdup (str);
  self->length = strlen (str);

  return res;
}

const char *
gtk_string_accessible_value_get (const GtkAccessibleValue *value)
{
  GtkStringAccessibleValue *self = (GtkStringAccessibleValue *) value;

  g_return_val_if_fail (value != NULL, 0);
  g_return_val_if_fail (value->value_class == >K_STRING_ACCESSIBLE_VALUE, 0);

  return self->value;
}

typedef struct {
  GtkAccessibleValue parent;

  GtkAccessible *ref;
} GtkReferenceAccessibleValue;

static void
remove_weak_ref (gpointer  data,
                 GObject  *old_reference)
{
  GtkReferenceAccessibleValue *self = data;

  self->ref = NULL;
}

static void
gtk_reference_accessible_value_finalize (GtkAccessibleValue *value)
{
  GtkReferenceAccessibleValue *self = (GtkReferenceAccessibleValue *) value;

  if (self->ref != NULL)
    g_object_weak_unref (G_OBJECT (self->ref), remove_weak_ref, self);
}

static gboolean
gtk_reference_accessible_value_equal (const GtkAccessibleValue *value_a,
                                      const GtkAccessibleValue *value_b)
{
  const GtkReferenceAccessibleValue *self_a = (GtkReferenceAccessibleValue *) value_a;
  const GtkReferenceAccessibleValue *self_b = (GtkReferenceAccessibleValue *) value_b;

  return self_a->ref == self_b->ref;
}

static void
gtk_reference_accessible_value_print (const GtkAccessibleValue *value,
                                      GString                  *buffer)
{
  const GtkReferenceAccessibleValue *self = (GtkReferenceAccessibleValue *) value;

  if (self->ref != NULL)
    {
      g_string_append_printf (buffer, "%s<%p>",
                              G_OBJECT_TYPE_NAME (self->ref),
                              self->ref);
    }
  else
    {
      g_string_append (buffer, "<null>");
    }
}

static const GtkAccessibleValueClass GTK_REFERENCE_ACCESSIBLE_VALUE = {
  .type = GTK_ACCESSIBLE_VALUE_TYPE_REFERENCE,
  .type_name = "GtkReferenceAccessibleValue",
  .instance_size = sizeof (GtkReferenceAccessibleValue),
  .finalize = gtk_reference_accessible_value_finalize,
  .equal = gtk_reference_accessible_value_equal,
  .print = gtk_reference_accessible_value_print,
};

GtkAccessibleValue *
gtk_reference_accessible_value_new (GtkAccessible *ref)
{
  g_return_val_if_fail (GTK_IS_ACCESSIBLE (ref), NULL);

  GtkAccessibleValue *res = gtk_accessible_value_alloc (>K_REFERENCE_ACCESSIBLE_VALUE);

  GtkReferenceAccessibleValue *self = (GtkReferenceAccessibleValue *) res;

  self->ref = ref;
  g_object_weak_ref (G_OBJECT (self->ref), remove_weak_ref, self);

  return res;
}

GtkAccessible *
gtk_reference_accessible_value_get (const GtkAccessibleValue *value)
{
  GtkReferenceAccessibleValue *self = (GtkReferenceAccessibleValue *) value;

  g_return_val_if_fail (value != NULL, 0);
  g_return_val_if_fail (value->value_class == >K_REFERENCE_ACCESSIBLE_VALUE, 0);

  return self->ref;
}

typedef struct {
  GtkAccessibleValue parent;

  GList *refs;
} GtkReferenceListAccessibleValue;

static void
remove_weak_ref_from_list (gpointer  data,
                           GObject  *old_reference)
{
  GtkReferenceListAccessibleValue *self = data;

  GList *item = g_list_find (self->refs, old_reference);

  if (item != NULL)
    {
      self->refs = g_list_remove_link (self->refs, item);
      g_list_free (item);
    }
}

static void
gtk_reference_list_accessible_value_finalize (GtkAccessibleValue *value)
{
  GtkReferenceListAccessibleValue *self = (GtkReferenceListAccessibleValue *) value;

  for (GList *l = self->refs; l != NULL; l = l->next)
    {
      if (l->data != NULL)
        g_object_weak_unref (G_OBJECT (l->data), remove_weak_ref_from_list, self);
    }

  g_list_free (self->refs);
}

static gboolean
gtk_reference_list_accessible_value_equal (const GtkAccessibleValue *value_a,
                                           const GtkAccessibleValue *value_b)
{
  const GtkReferenceListAccessibleValue *self_a = (GtkReferenceListAccessibleValue *) value_a;
  const GtkReferenceListAccessibleValue *self_b = (GtkReferenceListAccessibleValue *) value_b;

  if (g_list_length (self_a->refs) != g_list_length (self_b->refs))
    return FALSE;

  for (GList *l = self_a->refs; l != NULL; l = l->next)
    {
      if (g_list_find (self_b->refs, l->data) == NULL)
        return FALSE;
    }

  return TRUE;
}

static void
gtk_reference_list_accessible_value_print (const GtkAccessibleValue *value,
                                           GString                  *buffer)
{
  const GtkReferenceListAccessibleValue *self = (GtkReferenceListAccessibleValue *) value;

  if (self->refs == NULL)
    {
      g_string_append (buffer, "<null>");
      return;
    }

  for (GList *l = self->refs; l != NULL; l = l->next)
    {
      g_string_append_printf (buffer, "%s<%p>",
                              G_OBJECT_TYPE_NAME (l->data),
                              l->data);
    }
}

static const GtkAccessibleValueClass GTK_REFERENCE_LIST_ACCESSIBLE_VALUE = {
  .type = GTK_ACCESSIBLE_VALUE_TYPE_REFERENCE_LIST,
  .type_name = "GtkReferenceListAccessibleValue",
  .instance_size = sizeof (GtkReferenceListAccessibleValue),
  .finalize = gtk_reference_list_accessible_value_finalize,
  .equal = gtk_reference_list_accessible_value_equal,
  .print = gtk_reference_list_accessible_value_print,
};

/*< private >
 * gtk_reference_list_accessible_value_new:
 * @value: (element-type GtkAccessible) (transfer full): a list of accessible objects
 *
 * Creates a new `GtkAccessible` that stores a list of references
 * to `GtkAccessible` objects.
 *
 * Returns: (transfer full): the newly created `GtkAccessible`
 */

GtkAccessibleValue *
gtk_reference_list_accessible_value_new (GList *value)
{
  GtkAccessibleValue *res = gtk_accessible_value_alloc (>K_REFERENCE_LIST_ACCESSIBLE_VALUE);

  GtkReferenceListAccessibleValue *self = (GtkReferenceListAccessibleValue *) res;

  self->refs = value;
  if (self->refs != NULL)
    {
      for (GList *l = self->refs; l != NULL; l = l->next)
        g_object_weak_ref (l->data, remove_weak_ref_from_list, self);
    }

  return res;
}

GList *
gtk_reference_list_accessible_value_get (const GtkAccessibleValue *value)
{
  GtkReferenceListAccessibleValue *self = (GtkReferenceListAccessibleValue *) value;

  g_return_val_if_fail (value != NULL, 0);
  g_return_val_if_fail (value->value_class == >K_REFERENCE_LIST_ACCESSIBLE_VALUE, 0);

  return self->refs;
}

void
gtk_reference_list_accessible_value_append (GtkAccessibleValue *value,
                                            GtkAccessible      *ref)
{
  GtkReferenceListAccessibleValue *self = (GtkReferenceListAccessibleValue *) value;

  g_return_if_fail (value != NULL);
  g_return_if_fail (value->value_class == >K_REFERENCE_LIST_ACCESSIBLE_VALUE);

  if (g_list_find (self->refs, ref) != NULL)
    return;

  self->refs = g_list_append (self->refs, ref);

  g_object_weak_ref (G_OBJECT (ref), remove_weak_ref_from_list, self);
}

void
gtk_reference_list_accessible_value_remove (GtkAccessibleValue *value,
                                            GtkAccessible      *ref)
{
  GtkReferenceListAccessibleValue *self = (GtkReferenceListAccessibleValue *) value;

  g_return_if_fail (value != NULL);
  g_return_if_fail (value->value_class == >K_REFERENCE_LIST_ACCESSIBLE_VALUE);

  if (g_list_find (self->refs, ref) == NULL)
    {
      g_warning ("Trying to remove accessible '%s', but it cannot be found in "
                 "the reference list %p",
                 G_OBJECT_TYPE_NAME (ref),
                 value);
      return;
    }

  self->refs = g_list_remove (self->refs, ref);

  g_object_weak_unref (G_OBJECT (ref), remove_weak_ref_from_list, self);
}

/* }}} */

/* {{{ Collection API */

typedef enum {
  GTK_ACCESSIBLE_COLLECT_INVALID = -1,

  /* true/false */
  GTK_ACCESSIBLE_COLLECT_BOOLEAN = 0,

  /* true/false/mixed/undefined */
  GTK_ACCESSIBLE_COLLECT_TRISTATE,

  /* one token */
  GTK_ACCESSIBLE_COLLECT_TOKEN,

  /* integer number */
  GTK_ACCESSIBLE_COLLECT_INTEGER,

  /* real number */
  GTK_ACCESSIBLE_COLLECT_NUMBER,

  /* string */
  GTK_ACCESSIBLE_COLLECT_STRING,

  /* reference */
  GTK_ACCESSIBLE_COLLECT_REFERENCE,

  /* references list */
  GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,

  /* allows collecting GTK_ACCESSIBLE_VALUE_UNDEFINED; implied
   * by GTK_ACCESSIBLE_COLLECT_TRISTATE
   */

  GTK_ACCESSIBLE_COLLECT_UNDEFINED = 1 << 16
} GtkAccessibleCollectType;

typedef struct {
  int value;
  GtkAccessibleCollectType ctype;
  const char *name;

  /* The constructor and getter will be derived by the
   * @ctype field and by the collected value, except for the
   * GTK_ACCESSIBLE_COLLECT_TOKEN collection type. You can
   * override the default ones by filling out these two
   * pointers
   */

  GCallback ctor;
  GCallback getter;
  GCallback parser;
  GCallback init_value;
} GtkAccessibleCollect;

static const GtkAccessibleCollect collect_states[] = {
  [GTK_ACCESSIBLE_STATE_BUSY] = {
    .value = GTK_ACCESSIBLE_STATE_BUSY,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "busy"
  },
  [GTK_ACCESSIBLE_STATE_CHECKED] = {
    .value = GTK_ACCESSIBLE_STATE_CHECKED,
    .ctype = GTK_ACCESSIBLE_COLLECT_TRISTATE,
    .name = "checked"
  },
  [GTK_ACCESSIBLE_STATE_DISABLED] = {
    .value = GTK_ACCESSIBLE_STATE_DISABLED,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "disabled"
  },
  [GTK_ACCESSIBLE_STATE_EXPANDED] = {
    .value = GTK_ACCESSIBLE_STATE_EXPANDED,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN | GTK_ACCESSIBLE_COLLECT_UNDEFINED,
    .name = "expanded"
  },
  [GTK_ACCESSIBLE_STATE_HIDDEN] = {
    .value = GTK_ACCESSIBLE_STATE_HIDDEN,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "hidden"
  },
  [GTK_ACCESSIBLE_STATE_INVALID] = {
    .value = GTK_ACCESSIBLE_STATE_INVALID,
    .ctype = GTK_ACCESSIBLE_COLLECT_TOKEN,
    .name = "invalid",
    .ctor = (GCallback) gtk_invalid_accessible_value_new,
    .getter = (GCallback) gtk_invalid_accessible_value_get,
    .parser = (GCallback) gtk_invalid_accessible_value_parse,
    .init_value = (GCallback) gtk_invalid_accessible_value_init_value,
  },
  [GTK_ACCESSIBLE_STATE_PRESSED] = {
    .value = GTK_ACCESSIBLE_STATE_PRESSED,
    .ctype = GTK_ACCESSIBLE_COLLECT_TRISTATE,
    .name = "pressed"
  },
  [GTK_ACCESSIBLE_STATE_SELECTED] = {
    .value = GTK_ACCESSIBLE_STATE_SELECTED,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN | GTK_ACCESSIBLE_COLLECT_UNDEFINED,
    .name = "selected"
  },
  [GTK_ACCESSIBLE_STATE_VISITED] = {
    .value = GTK_ACCESSIBLE_STATE_VISITED,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN|GTK_ACCESSIBLE_COLLECT_UNDEFINED,
    .name = "visited"
  }
};

/* § 6.6.1 Widget attributes */
static const GtkAccessibleCollect collect_props[] = {
  [GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE] = {
    .value = GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE,
    .ctype = GTK_ACCESSIBLE_COLLECT_TOKEN,
    .name = "autocomplete",
    .ctor = (GCallback) gtk_autocomplete_accessible_value_new,
    .getter = (GCallback) gtk_autocomplete_accessible_value_get,
    .parser = (GCallback) gtk_autocomplete_accessible_value_parse,
    .init_value = (GCallback) gtk_autocomplete_accessible_value_init_value,
  },
  [GTK_ACCESSIBLE_PROPERTY_DESCRIPTION] = {
    .value = GTK_ACCESSIBLE_PROPERTY_DESCRIPTION,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "description"
  },
  [GTK_ACCESSIBLE_PROPERTY_HAS_POPUP] = {
    .value = GTK_ACCESSIBLE_PROPERTY_HAS_POPUP,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "haspopup"
  },
  [GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS] = {
    .value = GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "keyshortcuts"
  },
  [GTK_ACCESSIBLE_PROPERTY_LABEL] = {
    .value = GTK_ACCESSIBLE_PROPERTY_LABEL,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "label"
  },
  [GTK_ACCESSIBLE_PROPERTY_LEVEL] = {
    .value = GTK_ACCESSIBLE_PROPERTY_LEVEL,
    .ctype = GTK_ACCESSIBLE_COLLECT_INTEGER,
    .name = "level"
  },
  [GTK_ACCESSIBLE_PROPERTY_MODAL] = {
    .value = GTK_ACCESSIBLE_PROPERTY_MODAL,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "modal"
  },
  [GTK_ACCESSIBLE_PROPERTY_MULTI_LINE] = {
    .value = GTK_ACCESSIBLE_PROPERTY_MULTI_LINE,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "multiline"
  },
  [GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE] = {
    .value = GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "multiselectable"
  },
  /* "orientation" is a bit special; it maps to GtkOrientation, but it
   * can also be "undefined". This means we need to override constructor
   * and getter, in order to properly handle GTK_ACCESSIBLE_VALUE_UNDEFINED
   */

  [GTK_ACCESSIBLE_PROPERTY_ORIENTATION] = {
    .value = GTK_ACCESSIBLE_PROPERTY_ORIENTATION,
    .ctype = GTK_ACCESSIBLE_COLLECT_TOKEN | GTK_ACCESSIBLE_COLLECT_UNDEFINED,
    .name = "orientation",
    .ctor = (GCallback) gtk_orientation_accessible_value_new,
    .getter = (GCallback) gtk_orientation_accessible_value_get,
    .parser = (GCallback) gtk_orientation_accessible_value_parse,
    .init_value = (GCallback) gtk_orientation_accessible_value_init_value,
  },
  [GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER] = {
    .value = GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "placeholder"
  },
  [GTK_ACCESSIBLE_PROPERTY_READ_ONLY] = {
    .value = GTK_ACCESSIBLE_PROPERTY_READ_ONLY,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "readonly"
  },
  [GTK_ACCESSIBLE_PROPERTY_REQUIRED] = {
    .value = GTK_ACCESSIBLE_PROPERTY_REQUIRED,
    .ctype = GTK_ACCESSIBLE_COLLECT_BOOLEAN,
    .name = "required"
  },
  [GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION] = {
    .value = GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "roledescription"
  },
  [GTK_ACCESSIBLE_PROPERTY_SORT] = {
    .value = GTK_ACCESSIBLE_PROPERTY_SORT,
    .ctype = GTK_ACCESSIBLE_COLLECT_TOKEN,
    .name = "sort",
    .ctor = (GCallback) gtk_sort_accessible_value_new,
    .getter = (GCallback) gtk_sort_accessible_value_get,
    .parser = (GCallback) gtk_sort_accessible_value_parse,
    .init_value = (GCallback) gtk_sort_accessible_value_init_value,
  },
  [GTK_ACCESSIBLE_PROPERTY_VALUE_MAX] = {
    .value = GTK_ACCESSIBLE_PROPERTY_VALUE_MAX,
    .ctype = GTK_ACCESSIBLE_COLLECT_NUMBER,
    .name = "valuemax"
  },
  [GTK_ACCESSIBLE_PROPERTY_VALUE_MIN] = {
    .value = GTK_ACCESSIBLE_PROPERTY_VALUE_MIN,
    .ctype = GTK_ACCESSIBLE_COLLECT_NUMBER,
    .name = "valuemin"
  },
  [GTK_ACCESSIBLE_PROPERTY_VALUE_NOW] = {
    .value = GTK_ACCESSIBLE_PROPERTY_VALUE_NOW,
    .ctype = GTK_ACCESSIBLE_COLLECT_NUMBER,
    .name = "valuenow"
  },
  [GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT] = {
    .value = GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "valuetext"
  },
  [GTK_ACCESSIBLE_PROPERTY_HELP_TEXT] = {
    .value = GTK_ACCESSIBLE_PROPERTY_HELP_TEXT,
    .ctype = GTK_ACCESSIBLE_COLLECT_STRING,
    .name = "helptext"
  },
};

/* § 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_LIST,
    .name = "controls"
  },
  [GTK_ACCESSIBLE_RELATION_DESCRIBED_BY] = {
    .value = GTK_ACCESSIBLE_RELATION_DESCRIBED_BY,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "describedby"
  },
  [GTK_ACCESSIBLE_RELATION_DETAILS] = {
    .value = GTK_ACCESSIBLE_RELATION_DETAILS,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "details"
  },
  [GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE] = {
    .value = GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "errormessage"
  },
  [GTK_ACCESSIBLE_RELATION_FLOW_TO] = {
    .value = GTK_ACCESSIBLE_RELATION_FLOW_TO,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "flowto"
  },
  [GTK_ACCESSIBLE_RELATION_LABELLED_BY] = {
    .value = GTK_ACCESSIBLE_RELATION_LABELLED_BY,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "labelledby"
  },
  [GTK_ACCESSIBLE_RELATION_OWNS] = {
    .value = GTK_ACCESSIBLE_RELATION_OWNS,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .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 = "setsize"
  },
  [GTK_ACCESSIBLE_RELATION_LABEL_FOR] = {
    .value = GTK_ACCESSIBLE_RELATION_LABEL_FOR,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "labelfor"
  },
  [GTK_ACCESSIBLE_RELATION_DESCRIPTION_FOR] = {
    .value = GTK_ACCESSIBLE_RELATION_DESCRIPTION_FOR,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "descriptionfor"
  },
  [GTK_ACCESSIBLE_RELATION_CONTROLLED_BY] = {
    .value = GTK_ACCESSIBLE_RELATION_CONTROLLED_BY,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "controlledby"
  },
  [GTK_ACCESSIBLE_RELATION_DETAILS_FOR] = {
    .value = GTK_ACCESSIBLE_RELATION_DETAILS_FOR,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "detailsfor"
  },
  [GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE_FOR] = {
    .value = GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE_FOR,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "errormessagefor"
  },
  [GTK_ACCESSIBLE_RELATION_FLOW_FROM] = {
    .value = GTK_ACCESSIBLE_RELATION_FLOW_FROM,
    .ctype = GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST,
    .name = "flowfrom"
  },
};

typedef GtkAccessibleValue * (* GtkAccessibleValueBooleanCtor)  (gboolean value);
typedef GtkAccessibleValue * (* GtkAccessibleValueIntCtor)      (int value);
typedef GtkAccessibleValue * (* GtkAccessibleValueTristateCtor) (int value);
typedef GtkAccessibleValue * (* GtkAccessibleValueEnumCtor)     (int value);
typedef GtkAccessibleValue * (* GtkAccessibleValueNumberCtor)   (double value);
typedef GtkAccessibleValue * (* GtkAccessibleValueStringCtor)   (const char *value);
typedef GtkAccessibleValue * (* GtkAccessibleValueRefCtor)      (GtkAccessible *value);
typedef GtkAccessibleValue * (* GtkAccessibleValueRefListCtor)  (GList *value);

typedef GtkAccessibleValue * (* GtkAccessibleValueEnumParser)   (const char  *str,
                                                                 gsize        len,
                                                                 GError     **error);
typedef void                 (* GtkAccessibleValueEnumInit)     (GValue      *value);

/*< 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)
{
  const GtkAccessibleCollect *cstate = &collect_states[state];

  g_return_val_if_fail (state <= GTK_ACCESSIBLE_STATE_VISITED, NULL);

  switch (cstate->value)
    {
    case GTK_ACCESSIBLE_STATE_BUSY:
    case GTK_ACCESSIBLE_STATE_DISABLED:
    case GTK_ACCESSIBLE_STATE_HIDDEN:
      return gtk_boolean_accessible_value_new (FALSE);

    case GTK_ACCESSIBLE_STATE_CHECKED:
    case GTK_ACCESSIBLE_STATE_EXPANDED:
    case GTK_ACCESSIBLE_STATE_PRESSED:
    case GTK_ACCESSIBLE_STATE_SELECTED:
    case GTK_ACCESSIBLE_STATE_VISITED:
      return gtk_undefined_accessible_value_new ();

    case GTK_ACCESSIBLE_STATE_INVALID:
      return gtk_invalid_accessible_value_new (GTK_ACCESSIBLE_INVALID_FALSE);

    default:
      g_critical ("Unknown value for accessible state “%s”", cstate->name);
      break;
    }

  return NULL;
}

static GtkAccessibleValue *
gtk_accessible_value_collect_valist (const GtkAccessibleCollect  *cstate,
                                     GError                     **error,
                                     va_list                     *args)
{
  GtkAccessibleValue *res = NULL;
  GtkAccessibleCollectType ctype = cstate->ctype;
  gboolean collects_undef = (ctype & GTK_ACCESSIBLE_COLLECT_UNDEFINED) != 0;

  ctype &= (GTK_ACCESSIBLE_COLLECT_UNDEFINED - 1);

  /* Tristate values include "undefined" by definition */
  if (ctype == GTK_ACCESSIBLE_COLLECT_TRISTATE)
    collects_undef = TRUE;

  switch (ctype)
    {
    case GTK_ACCESSIBLE_COLLECT_BOOLEAN:
      {
        if (collects_undef)
          {
            int value = va_arg (*args, int);

            if (value == GTK_ACCESSIBLE_VALUE_UNDEFINED)
              res = gtk_undefined_accessible_value_new ();
            else
              res = gtk_boolean_accessible_value_new (value == 0 ? FALSE : TRUE);
          }
        else
          {
            gboolean value = va_arg (*args, gboolean);

            res = gtk_boolean_accessible_value_new (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TRISTATE:
      {
        int value = va_arg (*args, int);

        if (collects_undef && value == GTK_ACCESSIBLE_VALUE_UNDEFINED)
          res = gtk_undefined_accessible_value_new ();
        else
          res = gtk_tristate_accessible_value_new (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TOKEN:
      {
        GtkAccessibleValueEnumCtor ctor =
          (GtkAccessibleValueEnumCtor) cstate->ctor;

        int value = va_arg (*args, int);

        if (collects_undef && value == GTK_ACCESSIBLE_VALUE_UNDEFINED)
          {
            res = gtk_undefined_accessible_value_new ();
          }
        else
          {
            /* Token collection requires a constructor */
            g_assert (ctor != NULL);

            res = (* ctor) (value);
          }

        if (res == NULL)
          {
            g_set_error (error, GTK_ACCESSIBLE_VALUE_ERROR,
                         GTK_ACCESSIBLE_VALUE_ERROR_INVALID_TOKEN,
                         "Invalid value for token attribute: %d",
                         value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_INTEGER:
      {
        GtkAccessibleValueEnumCtor ctor =
          (GtkAccessibleValueEnumCtor) cstate->ctor;

        int value = va_arg (*args, int);

        if (ctor == NULL)
          res = gtk_int_accessible_value_new (value);
        else
          res = (* ctor) (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_NUMBER:
      {
        GtkAccessibleValueNumberCtor ctor =
          (GtkAccessibleValueNumberCtor) cstate->ctor;

        double value = va_arg (*args, double);

        if (isnan (value) || isinf (value))
          {
            g_set_error_literal (error, GTK_ACCESSIBLE_VALUE_ERROR,
                                 GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                                 "Invalid numeric value");
            return NULL;
          }

        if (ctor == NULL)
          res = gtk_number_accessible_value_new (value);
        else
          res = (* ctor) (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_STRING:
      {
        GtkAccessibleValueStringCtor ctor =
          (GtkAccessibleValueStringCtor) cstate->ctor;

        const char *value = va_arg (*args, char*);

        if (ctor == NULL)
          {
            if (value != NULL)
              res = gtk_string_accessible_value_new (value);
          }
        else
          {
            res = (* ctor) (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE:
      {
        GtkAccessibleValueRefCtor ctor =
          (GtkAccessibleValueRefCtor) cstate->ctor;

        gpointer value = va_arg (*args, gpointer);

        if (value != NULL && !GTK_IS_ACCESSIBLE (value))
          {
            g_set_error_literal (error, GTK_ACCESSIBLE_VALUE_ERROR,
                                 GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                                 "Reference does not implement GtkAccessible");
            return NULL;
          }

        if (ctor == NULL)
          {
            if (value != NULL)
              res = gtk_reference_accessible_value_new (value);
            else
              res = gtk_undefined_accessible_value_new ();
          }
        else
          {
            res = (* ctor) (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST:
      {
        GtkAccessibleValueRefListCtor ctor =
          (GtkAccessibleValueRefListCtor) cstate->ctor;

        GtkAccessible *ref = va_arg (*args, gpointer);
        GList *value = NULL;

        while (ref != NULL)
          {
            if (!GTK_IS_ACCESSIBLE (ref))
              {
                g_set_error (error, GTK_ACCESSIBLE_VALUE_ERROR,
                             GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                             "Reference of type “%s” [%p] does not implement GtkAccessible",
                             G_OBJECT_TYPE_NAME (ref), ref);
                return NULL;
              }

            value = g_list_prepend (value, ref);

            ref = va_arg (*args, gpointer);
          }

        if (value == NULL)
          res = gtk_undefined_accessible_value_new ();
        else
          {
            value = g_list_reverse (value);

            if (ctor == NULL)
              res = gtk_reference_list_accessible_value_new (value);
            else
              res = (* ctor) (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_UNDEFINED:
    case GTK_ACCESSIBLE_COLLECT_INVALID:
    default:
      g_assert_not_reached ();
      break;
    }

  return res;
}

static GtkAccessibleValue *
gtk_accessible_value_collect_value (const GtkAccessibleCollect  *cstate,
                                    const GValue                *value_,
                                    GError                     **error)
{
  GtkAccessibleValue *res = NULL;
  GtkAccessibleCollectType ctype = cstate->ctype;
  gboolean collects_undef = (ctype & GTK_ACCESSIBLE_COLLECT_UNDEFINED) != 0;

  ctype &= (GTK_ACCESSIBLE_COLLECT_UNDEFINED - 1);

  /* Tristate values include "undefined" by definition */
  if (ctype == GTK_ACCESSIBLE_COLLECT_TRISTATE)
    collects_undef = TRUE;

  switch (ctype)
    {
    case GTK_ACCESSIBLE_COLLECT_BOOLEAN:
      {
        if (collects_undef)
          {
            int value = g_value_get_int (value_);

            if (value == GTK_ACCESSIBLE_VALUE_UNDEFINED)
              res = gtk_undefined_accessible_value_new ();
            else
              res = gtk_boolean_accessible_value_new (value == 0 ? FALSE : TRUE);
          }
        else
          {
            gboolean value = g_value_get_boolean (value_);

            res = gtk_boolean_accessible_value_new (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TRISTATE:
      {
        int value = g_value_get_int (value_);

        if (collects_undef && value == GTK_ACCESSIBLE_VALUE_UNDEFINED)
          res = gtk_undefined_accessible_value_new ();
        else
          res = gtk_tristate_accessible_value_new (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TOKEN:
      {
        GtkAccessibleValueEnumCtor ctor =
          (GtkAccessibleValueEnumCtor) cstate->ctor;

        int value = g_value_get_int (value_);

        if (collects_undef && value == GTK_ACCESSIBLE_VALUE_UNDEFINED)
          {
            res = gtk_undefined_accessible_value_new ();
          }
        else
          {
            /* Token collection requires a constructor */
            g_assert (ctor != NULL);

            res = (* ctor) (value);
          }

        if (res == NULL)
          {
            g_set_error (error, GTK_ACCESSIBLE_VALUE_ERROR,
                         GTK_ACCESSIBLE_VALUE_ERROR_INVALID_TOKEN,
                         "Invalid value for token attribute: %d",
                         value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_INTEGER:
      {
        GtkAccessibleValueEnumCtor ctor =
          (GtkAccessibleValueEnumCtor) cstate->ctor;

        int value = g_value_get_int (value_);

        if (ctor == NULL)
          res = gtk_int_accessible_value_new (value);
        else
          res = (* ctor) (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_NUMBER:
      {
        GtkAccessibleValueNumberCtor ctor =
          (GtkAccessibleValueNumberCtor) cstate->ctor;

        double value = g_value_get_double (value_);

        if (isnan (value) || isinf (value))
          {
            g_set_error_literal (error, GTK_ACCESSIBLE_VALUE_ERROR,
                                 GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                                 "Invalid numeric value");
            return NULL;
          }

        if (ctor == NULL)
          res = gtk_number_accessible_value_new (value);
        else
          res = (* ctor) (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_STRING:
      {
        GtkAccessibleValueStringCtor ctor =
          (GtkAccessibleValueStringCtor) cstate->ctor;

        const char *value = g_value_get_string (value_);

        if (ctor == NULL)
          {
            if (value != NULL)
              res = gtk_string_accessible_value_new (value);
          }
        else
          {
            res = (* ctor) (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE:
      {
        GtkAccessibleValueRefCtor ctor =
          (GtkAccessibleValueRefCtor) cstate->ctor;

        gpointer value = g_value_get_object (value_);

        if (value != NULL && !GTK_IS_ACCESSIBLE (value))
          {
            g_set_error_literal (error, GTK_ACCESSIBLE_VALUE_ERROR,
                                 GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                                 "Reference does not implement GtkAccessible");
            return NULL;
          }

        if (ctor == NULL)
          {
            if (value != NULL)
              res = gtk_reference_accessible_value_new (value);
          }
        else
          {
            res = (* ctor) (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST:
      {
        GtkAccessibleValueRefListCtor ctor =
          (GtkAccessibleValueRefListCtor) cstate->ctor;

        GList *value;

        if (g_type_is_a (G_VALUE_TYPE(value_), GTK_ACCESSIBLE_LIST))
          {
            GtkAccessibleList *boxed = g_value_get_boxed (value_);

            value = gtk_accessible_list_get_objects (boxed);
          }
        else
          {
            value = g_list_copy (g_value_get_pointer (value_));
          }

        if (ctor == NULL)
          {
            if (value != NULL)
              res = gtk_reference_list_accessible_value_new (value);
          }
        else
          {
            res = (* ctor) (value);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_UNDEFINED:
    case GTK_ACCESSIBLE_COLLECT_INVALID:
    default:
      g_assert_not_reached ();
      break;
    }

  return res;
}

static GtkAccessibleValue *
gtk_accessible_value_parse (const GtkAccessibleCollect  *cstate,
                            const char                  *str,
                            gsize                        len,
                            GError                     **error)
{
  GtkAccessibleValue *res = NULL;
  GtkAccessibleCollectType ctype = cstate->ctype;
  gboolean collects_undef = (ctype & GTK_ACCESSIBLE_COLLECT_UNDEFINED) != 0;

  ctype &= (GTK_ACCESSIBLE_COLLECT_UNDEFINED - 1);

  /* Tristate values include "undefined" by definition */
  if (ctype == GTK_ACCESSIBLE_COLLECT_TRISTATE)
    collects_undef = TRUE;

  switch (ctype)
    {
    case GTK_ACCESSIBLE_COLLECT_BOOLEAN:
      {
        gboolean b;

        if (collects_undef && strncmp (str, "undefined"9) == 0)
          res = gtk_undefined_accessible_value_new ();
        else if (_gtk_builder_boolean_from_string (str, &b, error))
          res = gtk_boolean_accessible_value_new (b);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TRISTATE:
      {
        int value;

        if (collects_undef && strncmp (str, "undefined"9) == 0)
          res = gtk_undefined_accessible_value_new ();
        else if (_gtk_builder_enum_from_string (GTK_TYPE_ACCESSIBLE_TRISTATE, str, &value, error))
          res = gtk_boolean_accessible_value_new (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TOKEN:
      {
        GtkAccessibleValueEnumParser parser =
          (GtkAccessibleValueEnumParser) cstate->parser;

        if (collects_undef && strncmp (str, "undefined"9) == 0)
          {
            res = gtk_undefined_accessible_value_new ();
          }
        else
          {
            /* Token collection requires a constructor */
            g_assert (parser != NULL);

            res = (* parser) (str, len, error);
          }
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_INTEGER:
      {
        char *end = NULL;
        gint64 value = g_ascii_strtoll (str, &end, 10);

        if (str == end)
          {
            int saved_errno = errno;
            g_set_error (error, GTK_ACCESSIBLE_VALUE_ERROR,
                         GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                         "Invalid integer value “%s”: %s",
                         str, g_strerror (saved_errno));

            return NULL;
          }
        else
          res = gtk_int_accessible_value_new ((int) value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_NUMBER:
      {
        char *end = NULL;
        double value = g_ascii_strtod (str, &end);

        if (str == end || isnan (value) || isinf (value))
          {
            g_set_error (error, GTK_ACCESSIBLE_VALUE_ERROR,
                         GTK_ACCESSIBLE_VALUE_ERROR_INVALID_VALUE,
                         "Invalid numeric value “%s”",
                         str);
            return NULL;
          }

        res = gtk_number_accessible_value_new (value);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_STRING:
      {
        res = gtk_string_accessible_value_new (str);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE:
    case GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST:
      {
        /* We do not error out, to let the caller code deal
         * with the references themselves
         */

        res = NULL;
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_UNDEFINED:
    case GTK_ACCESSIBLE_COLLECT_INVALID:
    default:
      g_assert_not_reached ();
      break;
    }

  return res;
}

static void
gtk_accessible_attribute_init_value (const GtkAccessibleCollect *cstate,
                                     GValue                     *value)
{
  GtkAccessibleCollectType ctype = cstate->ctype;
  gboolean collects_undef = (ctype & GTK_ACCESSIBLE_COLLECT_UNDEFINED) != 0;

  ctype &= (GTK_ACCESSIBLE_COLLECT_UNDEFINED - 1);

  /* Tristate values include "undefined" by definition */
  if (ctype == GTK_ACCESSIBLE_COLLECT_TRISTATE)
    collects_undef = TRUE;

  switch (ctype)
    {
    case GTK_ACCESSIBLE_COLLECT_BOOLEAN:
      {
        if (collects_undef)
          g_value_init (value, G_TYPE_INT);
        else
          g_value_init (value, G_TYPE_BOOLEAN);
      }
      break;

    case GTK_ACCESSIBLE_COLLECT_TRISTATE:
      g_value_init (value, GTK_TYPE_ACCESSIBLE_TRISTATE);
      break;

    case GTK_ACCESSIBLE_COLLECT_TOKEN:
      if (cstate->init_value != NULL)
        {
          GtkAccessibleValueEnumInit init_value =
            (GtkAccessibleValueEnumInit) cstate->init_value;

          (* init_value) (value);
        }
      else
        g_value_init (value, G_TYPE_INT);
      break;

    case GTK_ACCESSIBLE_COLLECT_INTEGER:
      g_value_init (value, G_TYPE_INT);
      break;

    case GTK_ACCESSIBLE_COLLECT_NUMBER:
      g_value_init (value, G_TYPE_DOUBLE);
      break;

    case GTK_ACCESSIBLE_COLLECT_STRING:
      g_value_init (value, G_TYPE_STRING);
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE:
      g_value_init (value, GTK_TYPE_ACCESSIBLE);
      break;

    case GTK_ACCESSIBLE_COLLECT_REFERENCE_LIST:
      g_value_init (value, G_TYPE_POINTER);
      break;

    case GTK_ACCESSIBLE_COLLECT_UNDEFINED:
    case GTK_ACCESSIBLE_COLLECT_INVALID:
    default:
      g_assert_not_reached ();
      break;
    }
}

/*< private >
 * gtk_accessible_value_collect_for_state:
 * @state: a `GtkAccessibleState`
 * @error: return location for a `GError`
 * @args: a `va_list` reference
 *
 * Collects and consumes the next item in the @args variadic arguments list,
 * and returns a `GtkAccessibleValue` for it.
 *
 * If the collection fails, @error is set and %NULL is returned.
 *
 * The returned value could be %NULL even on success, in which case the state
 * should be reset to its default value by the caller.
 *
 * Returns: (transfer full) (nullable): a `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_collect_for_state (GtkAccessibleState   state,
                                        GError             **error,
                                        va_list             *args)
{
  const GtkAccessibleCollect *cstate = &collect_states[state];

  g_return_val_if_fail (state <= GTK_ACCESSIBLE_STATE_VISITED, NULL);

  return gtk_accessible_value_collect_valist (cstate, error, args);
}

/*< private >
 * gtk_accessible_value_collect_for_state_value:
 * @state: a `GtkAccessibleState`
 * @value: a `GValue`
 * @error: return location for a `GError`
 *
 * Retrieves the value stored inside @value and returns a `GtkAccessibleValue`
 * for the given @state.
 *
 * If the collection fails, @error is set and %NULL is returned.
 *
 * The returned value could be %NULL even on success, in which case the state
 * should be reset to its default value by the caller.
 *
 * Returns: (transfer full) (nullable): a `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_collect_for_state_value (GtkAccessibleState   state,
                                              const GValue        *value,
                                              GError             **error)
{
  const GtkAccessibleCollect *cstate = &collect_states[state];

  g_return_val_if_fail (state <= GTK_ACCESSIBLE_STATE_VISITED, NULL);

  return gtk_accessible_value_collect_value (cstate, value, error);
}

GtkAccessibleValue *
gtk_accessible_value_parse_for_state (GtkAccessibleState   state,
                                      const char          *str,
                                      gsize                len,
                                      GError             **error)
{
  const GtkAccessibleCollect *cstate = &collect_states[state];

  g_return_val_if_fail (state <= GTK_ACCESSIBLE_STATE_VISITED, NULL);

  return gtk_accessible_value_parse (cstate, str, len, error);
}

/**
 * gtk_accessible_state_init_value:
 * @state: a `GtkAccessibleState`
 * @value: an uninitialized `GValue`
 *
 * Initializes @value with the appropriate type for the @state.
 *
 * This function is mostly meant for language bindings, in conjunction
 * with gtk_accessible_update_relation_state().
 */

void
gtk_accessible_state_init_value (GtkAccessibleState  state,
                                 GValue             *value)
{
  const GtkAccessibleCollect *cstate = &collect_states[state];

  g_return_if_fail (state <= GTK_ACCESSIBLE_STATE_SELECTED);

  gtk_accessible_attribute_init_value (cstate, value);
}

/*< private >
 * gtk_accessible_value_get_default_for_property:
 * @property: a `GtkAccessibleProperty`
 *
 * Retrieves the `GtkAccessibleValue` that contains the default for the
 * given @property.
 *
 * Returns: (transfer full): the `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_get_default_for_property (GtkAccessibleProperty property)
{
  const GtkAccessibleCollect *cstate = &collect_props[property];

  g_return_val_if_fail (property <= GTK_ACCESSIBLE_PROPERTY_HELP_TEXT, NULL);

  switch (cstate->value)
    {
    /* Boolean properties */
    case GTK_ACCESSIBLE_PROPERTY_HAS_POPUP:
    case GTK_ACCESSIBLE_PROPERTY_MODAL:
    case GTK_ACCESSIBLE_PROPERTY_MULTI_LINE:
    case GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE:
    case GTK_ACCESSIBLE_PROPERTY_READ_ONLY:
    case GTK_ACCESSIBLE_PROPERTY_REQUIRED:
      return gtk_boolean_accessible_value_new (FALSE);

    /* Integer properties */
    case GTK_ACCESSIBLE_PROPERTY_LEVEL:
      return gtk_int_accessible_value_new (0);

    /* Number properties */
    case GTK_ACCESSIBLE_PROPERTY_VALUE_MAX:
    case GTK_ACCESSIBLE_PROPERTY_VALUE_MIN:
    case GTK_ACCESSIBLE_PROPERTY_VALUE_NOW:
      return gtk_number_accessible_value_new (0);

    /* String properties */
    case GTK_ACCESSIBLE_PROPERTY_DESCRIPTION:
    case GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS:
    case GTK_ACCESSIBLE_PROPERTY_LABEL:
    case GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER:
    case GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION:
    case GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT:
    case GTK_ACCESSIBLE_PROPERTY_HELP_TEXT:
      return gtk_undefined_accessible_value_new ();

    /* Token properties */
    case GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE:
      return gtk_autocomplete_accessible_value_new (GTK_ACCESSIBLE_AUTOCOMPLETE_NONE);

    case GTK_ACCESSIBLE_PROPERTY_ORIENTATION:
      return gtk_undefined_accessible_value_new ();

    case GTK_ACCESSIBLE_PROPERTY_SORT:
      return gtk_sort_accessible_value_new (GTK_ACCESSIBLE_SORT_NONE);

    default:
      g_critical ("Unknown value for accessible property “%s”", cstate->name);
      break;
    }

  return NULL;
}

/*< private >
 * gtk_accessible_value_collect_for_property:
 * @property: a `GtkAccessibleProperty`
 * @error: return location for a `GError`
 * @args: a `va_list` reference
 *
 * Collects and consumes the next item in the @args variadic arguments list,
 * and returns a `GtkAccessibleValue` for it.
 *
 * If the collection fails, @error is set.
 *
 * Returns: (transfer full) (nullable): a `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_collect_for_property (GtkAccessibleProperty   property,
                                           GError                **error,
                                           va_list                *args)
{
  const GtkAccessibleCollect *cstate = &collect_props[property];

  g_return_val_if_fail (property <= GTK_ACCESSIBLE_PROPERTY_HELP_TEXT, NULL);

  return gtk_accessible_value_collect_valist (cstate, error, args);
}

/*< private >
 * gtk_accessible_value_collect_for_property_value:
 * @property: a `GtkAccessibleProperty`
 * @value: a `GValue`
 * @error: return location for a `GError`
 *
 * Retrieves the value stored inside @value and returns a `GtkAccessibleValue`
 * for the given @property.
 *
 * If the collection fails, @error is set.
 *
 * The returned value could be %NULL even on success, in which case the property
 * should be reset to its default value by the caller.
 *
 * Returns: (transfer full) (nullable): a `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_collect_for_property_value (GtkAccessibleProperty   property,
                                                 const GValue           *value,
                                                 GError                **error)
{
  const GtkAccessibleCollect *cstate = &collect_props[property];

  g_return_val_if_fail (property <= GTK_ACCESSIBLE_PROPERTY_HELP_TEXT, NULL);

  return gtk_accessible_value_collect_value (cstate, value, error);
}

GtkAccessibleValue *
gtk_accessible_value_parse_for_property (GtkAccessibleProperty   property,
                                         const char             *str,
                                         gsize                   len,
                                         GError                **error)
{
  const GtkAccessibleCollect *cstate = &collect_props[property];

  g_return_val_if_fail (property <= GTK_ACCESSIBLE_PROPERTY_HELP_TEXT, NULL);

  return gtk_accessible_value_parse (cstate, str, len, error);
}

/**
 * gtk_accessible_property_init_value:
 * @property: a `GtkAccessibleProperty`
 * @value: an uninitialized `GValue`
 *
 * Initializes @value with the appropriate type for the @property.
 *
 * This function is mostly meant for language bindings, in conjunction
 * with gtk_accessible_update_property_value().
 */

void
gtk_accessible_property_init_value (GtkAccessibleProperty  property,
                                    GValue                *value)
{
  const GtkAccessibleCollect *cstate = &collect_props[property];

  g_return_if_fail (property <= GTK_ACCESSIBLE_PROPERTY_HELP_TEXT);

  gtk_accessible_attribute_init_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];

  g_return_val_if_fail (relation <= GTK_ACCESSIBLE_RELATION_FLOW_FROM, NULL);

  switch (cstate->value)
    {
    /* References */
    case GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT:
    case GTK_ACCESSIBLE_RELATION_CONTROLS:
    case GTK_ACCESSIBLE_RELATION_CONTROLLED_BY:
    case GTK_ACCESSIBLE_RELATION_DESCRIBED_BY:
    case GTK_ACCESSIBLE_RELATION_DESCRIPTION_FOR:
    case GTK_ACCESSIBLE_RELATION_DETAILS:
    case GTK_ACCESSIBLE_RELATION_DETAILS_FOR:
    case GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE:
    case GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE_FOR:
    case GTK_ACCESSIBLE_RELATION_FLOW_FROM:
    case GTK_ACCESSIBLE_RELATION_FLOW_TO:
    case GTK_ACCESSIBLE_RELATION_LABELLED_BY:
    case GTK_ACCESSIBLE_RELATION_LABEL_FOR:
    case GTK_ACCESSIBLE_RELATION_OWNS:
      return gtk_undefined_accessible_value_new ();

    /* 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_undefined_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`
 * @error: return location for a `GError`
 * @args: a `va_list` reference
 *
 * Collects and consumes the next item in the @args variadic arguments list,
 * and returns a `GtkAccessibleValue` for it.
 *
 * If the collection fails, @error is set and %NULL is returned.
 *
 * The returned value could be %NULL even on success, in which case the relation
 * should be reset to its default value by the caller.
 *
 * Returns: (transfer full) (nullable): a `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_collect_for_relation (GtkAccessibleRelation   relation,
                                           GError                **error,
                                           va_list                *args)
{
  const GtkAccessibleCollect *cstate = &collect_rels[relation];

  g_return_val_if_fail (relation <= GTK_ACCESSIBLE_RELATION_FLOW_FROM, NULL);

  return gtk_accessible_value_collect_valist (cstate, error, args);
}

/*< private >
 * gtk_accessible_value_collect_for_relation_value:
 * @relation: a `GtkAccessibleRelation`
 * @value: a `GValue`
 * @error: return location for a `GError`
 *
 * Retrieves the value stored inside @value and returns a `GtkAccessibleValue`
 * for the given @relation.
 *
 * If the collection fails, @error is set and %NULL is returned.
 *
 * The returned value could be %NULL even on success, in which case the relation
 * should be reset to its default value by the caller.
 *
 * Returns: (transfer full) (nullable): a `GtkAccessibleValue`
 */

GtkAccessibleValue *
gtk_accessible_value_collect_for_relation_value (GtkAccessibleRelation   relation,
                                                 const GValue           *value,
                                                 GError                **error)
{
  const GtkAccessibleCollect *cstate = &collect_rels[relation];

  g_return_val_if_fail (relation <= GTK_ACCESSIBLE_RELATION_FLOW_FROM, NULL);

  return gtk_accessible_value_collect_value (cstate, value, error);
}

GtkAccessibleValue *
gtk_accessible_value_parse_for_relation (GtkAccessibleRelation   relation,
                                         const char             *str,
                                         gsize                   len,
                                         GError                **error)
{
  const GtkAccessibleCollect *cstate = &collect_rels[relation];

  g_return_val_if_fail (relation <= GTK_ACCESSIBLE_RELATION_FLOW_FROM, NULL);

  return gtk_accessible_value_parse (cstate, str, len, error);
}

/**
 * gtk_accessible_relation_init_value:
 * @relation: a `GtkAccessibleRelation`
 * @value: an uninitialized `GValue`
 *
 * Initializes @value with the appropriate type for the @relation.
 *
 * This function is mostly meant for language bindings, in conjunction
 * with gtk_accessible_update_relation_value().
 */

void
gtk_accessible_relation_init_value (GtkAccessibleRelation  relation,
                                    GValue                *value)
{
  const GtkAccessibleCollect *cstate = &collect_rels[relation];

  g_return_if_fail (relation <= GTK_ACCESSIBLE_RELATION_FLOW_FROM);

  gtk_accessible_attribute_init_value (cstate, value);
}

/* }}} */

Messung V0.5 in Prozent
C=98 H=96 G=96

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik