forked from AuroraMiddleware/gtk
b5ee73d299
Add an enum for 'platform changes' to the at context change notification mechanism. This will let us pass along things that ARIA considers 'platform state' such as focus or editability. The difference between the platform state and other ARIA states is that we don't keep the platform state separately in the at context - backends are expected to just query the widgets. This is just about avoiding notify listeners for change notification.
821 lines
25 KiB
C
821 lines
25 KiB
C
/* gtkatcontext.c: Assistive technology context
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:gtkatcontext
|
|
* @Title: GtkATContext
|
|
* @Short_description: An object communicating to Assistive Technologies
|
|
*
|
|
* GtkATContext is an abstract class provided by GTK to communicate to
|
|
* platform-specific assistive technologies API.
|
|
*
|
|
* Each platform supported by GTK implements a #GtkATContext subclass, and
|
|
* is responsible for updating the accessible state in response to state
|
|
* changes in #GtkAccessible.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gtkatcontextprivate.h"
|
|
|
|
#include "gtkaccessiblevalueprivate.h"
|
|
#include "gtkaccessibleprivate.h"
|
|
#include "gtkdebug.h"
|
|
#include "gtktestatcontextprivate.h"
|
|
#include "gtktypebuiltins.h"
|
|
|
|
#if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WAYLAND)
|
|
#include "a11y/gtkatspicontextprivate.h"
|
|
#endif
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (GtkATContext, gtk_at_context, G_TYPE_OBJECT)
|
|
|
|
enum
|
|
{
|
|
PROP_ACCESSIBLE_ROLE = 1,
|
|
PROP_ACCESSIBLE,
|
|
PROP_DISPLAY,
|
|
|
|
N_PROPS
|
|
};
|
|
|
|
enum
|
|
{
|
|
STATE_CHANGE,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static GParamSpec *obj_props[N_PROPS];
|
|
|
|
static guint obj_signals[LAST_SIGNAL];
|
|
|
|
static void
|
|
gtk_at_context_finalize (GObject *gobject)
|
|
{
|
|
GtkATContext *self = GTK_AT_CONTEXT (gobject);
|
|
|
|
gtk_accessible_attribute_set_unref (self->properties);
|
|
gtk_accessible_attribute_set_unref (self->relations);
|
|
gtk_accessible_attribute_set_unref (self->states);
|
|
|
|
G_OBJECT_CLASS (gtk_at_context_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static void
|
|
gtk_at_context_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkATContext *self = GTK_AT_CONTEXT (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_ACCESSIBLE_ROLE:
|
|
self->accessible_role = g_value_get_enum (value);
|
|
break;
|
|
|
|
case PROP_ACCESSIBLE:
|
|
self->accessible = g_value_get_object (value);
|
|
break;
|
|
|
|
case PROP_DISPLAY:
|
|
self->display = g_value_get_object (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_at_context_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkATContext *self = GTK_AT_CONTEXT (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_ACCESSIBLE_ROLE:
|
|
g_value_set_enum (value, self->accessible_role);
|
|
break;
|
|
|
|
case PROP_ACCESSIBLE:
|
|
g_value_set_object (value, self->accessible);
|
|
break;
|
|
|
|
case PROP_DISPLAY:
|
|
g_value_set_object (value, self->display);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_at_context_real_state_change (GtkATContext *self,
|
|
GtkAccessibleStateChange changed_states,
|
|
GtkAccessiblePropertyChange changed_properties,
|
|
GtkAccessibleRelationChange changed_relations,
|
|
GtkAccessiblePlatformChange changed_platform,
|
|
GtkAccessibleAttributeSet *states,
|
|
GtkAccessibleAttributeSet *properties,
|
|
GtkAccessibleAttributeSet *relations)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gtk_at_context_class_init (GtkATContextClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->set_property = gtk_at_context_set_property;
|
|
gobject_class->get_property = gtk_at_context_get_property;
|
|
gobject_class->finalize = gtk_at_context_finalize;
|
|
|
|
klass->state_change = gtk_at_context_real_state_change;
|
|
|
|
/**
|
|
* GtkATContext:accessible-role:
|
|
*
|
|
* The accessible role used by the AT context.
|
|
*
|
|
* Depending on the given role, different states and properties can be
|
|
* set or retrieved.
|
|
*/
|
|
obj_props[PROP_ACCESSIBLE_ROLE] =
|
|
g_param_spec_enum ("accessible-role",
|
|
"Accessible Role",
|
|
"The accessible role of the AT context",
|
|
GTK_TYPE_ACCESSIBLE_ROLE,
|
|
GTK_ACCESSIBLE_ROLE_NONE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* GtkATContext:accessible:
|
|
*
|
|
* The #GtkAccessible that created the #GtkATContext instance.
|
|
*/
|
|
obj_props[PROP_ACCESSIBLE] =
|
|
g_param_spec_object ("accessible",
|
|
"Accessible",
|
|
"The accessible implementation",
|
|
GTK_TYPE_ACCESSIBLE,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* GtkATContext:display:
|
|
*
|
|
* The #GdkDisplay for the #GtkATContext.
|
|
*/
|
|
obj_props[PROP_DISPLAY] =
|
|
g_param_spec_object ("display",
|
|
"Display",
|
|
"The display connection",
|
|
GDK_TYPE_DISPLAY,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* GtkATContext::state-change:
|
|
* @self: the #GtkATContext
|
|
*
|
|
* Emitted when the attributes of the accessible for the
|
|
* #GtkATContext instance change.
|
|
*/
|
|
obj_signals[STATE_CHANGE] =
|
|
g_signal_new ("state-change",
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL, NULL,
|
|
NULL,
|
|
G_TYPE_NONE, 0);
|
|
|
|
g_object_class_install_properties (gobject_class, N_PROPS, obj_props);
|
|
}
|
|
|
|
#define N_PROPERTIES (GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT + 1)
|
|
#define N_RELATIONS (GTK_ACCESSIBLE_RELATION_SET_SIZE + 1)
|
|
#define N_STATES (GTK_ACCESSIBLE_STATE_SELECTED + 1)
|
|
|
|
static const char *property_attrs[] = {
|
|
[GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE] = "autocomplete",
|
|
[GTK_ACCESSIBLE_PROPERTY_DESCRIPTION] = "description",
|
|
[GTK_ACCESSIBLE_PROPERTY_HAS_POPUP] = "haspopup",
|
|
[GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS] = "keyshortcuts",
|
|
[GTK_ACCESSIBLE_PROPERTY_LABEL] = "label",
|
|
[GTK_ACCESSIBLE_PROPERTY_LEVEL] = "level",
|
|
[GTK_ACCESSIBLE_PROPERTY_MODAL] = "modal",
|
|
[GTK_ACCESSIBLE_PROPERTY_MULTI_LINE] = "multiline",
|
|
[GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE] = "multiselectable",
|
|
[GTK_ACCESSIBLE_PROPERTY_ORIENTATION] = "orientation",
|
|
[GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER] = "placeholder",
|
|
[GTK_ACCESSIBLE_PROPERTY_READ_ONLY] = "readonly",
|
|
[GTK_ACCESSIBLE_PROPERTY_REQUIRED] = "required",
|
|
[GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION] = "roledescription",
|
|
[GTK_ACCESSIBLE_PROPERTY_SORT] = "sort",
|
|
[GTK_ACCESSIBLE_PROPERTY_VALUE_MAX] = "valuemax",
|
|
[GTK_ACCESSIBLE_PROPERTY_VALUE_MIN] = "valuemin",
|
|
[GTK_ACCESSIBLE_PROPERTY_VALUE_NOW] = "valuenow",
|
|
[GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT] = "valuetext",
|
|
};
|
|
|
|
/*< private >
|
|
* gtk_accessible_property_get_attribute_name:
|
|
* @property: a #GtkAccessibleProperty
|
|
*
|
|
* Retrieves the name of a #GtkAccessibleProperty.
|
|
*
|
|
* Returns: (transfer none): the name of the accessible property
|
|
*/
|
|
const char *
|
|
gtk_accessible_property_get_attribute_name (GtkAccessibleProperty property)
|
|
{
|
|
g_return_val_if_fail (property >= GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE &&
|
|
property <= GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT,
|
|
"<none>");
|
|
|
|
return property_attrs[property];
|
|
}
|
|
|
|
static const char *relation_attrs[] = {
|
|
[GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT] = "activedescendant",
|
|
[GTK_ACCESSIBLE_RELATION_COL_COUNT] = "colcount",
|
|
[GTK_ACCESSIBLE_RELATION_COL_INDEX] = "colindex",
|
|
[GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT] = "colindextext",
|
|
[GTK_ACCESSIBLE_RELATION_COL_SPAN] = "colspan",
|
|
[GTK_ACCESSIBLE_RELATION_CONTROLS] = "controls",
|
|
[GTK_ACCESSIBLE_RELATION_DESCRIBED_BY] = "describedby",
|
|
[GTK_ACCESSIBLE_RELATION_DETAILS] = "details",
|
|
[GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE] = "errormessage",
|
|
[GTK_ACCESSIBLE_RELATION_FLOW_TO] = "flowto",
|
|
[GTK_ACCESSIBLE_RELATION_LABELLED_BY] = "labelledby",
|
|
[GTK_ACCESSIBLE_RELATION_OWNS] = "owns",
|
|
[GTK_ACCESSIBLE_RELATION_POS_IN_SET] = "posinset",
|
|
[GTK_ACCESSIBLE_RELATION_ROW_COUNT] = "rowcount",
|
|
[GTK_ACCESSIBLE_RELATION_ROW_INDEX] = "rowindex",
|
|
[GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT] = "rowindextext",
|
|
[GTK_ACCESSIBLE_RELATION_ROW_SPAN] = "rowspan",
|
|
[GTK_ACCESSIBLE_RELATION_SET_SIZE] = "setsize",
|
|
};
|
|
|
|
/*< private >
|
|
* gtk_accessible_relation_get_attribute_name:
|
|
* @relation: a #GtkAccessibleRelation
|
|
*
|
|
* Retrieves the name of a #GtkAccessibleRelation.
|
|
*
|
|
* Returns: (transfer none): the name of the accessible relation
|
|
*/
|
|
const char *
|
|
gtk_accessible_relation_get_attribute_name (GtkAccessibleRelation relation)
|
|
{
|
|
g_return_val_if_fail (relation >= GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT &&
|
|
relation <= GTK_ACCESSIBLE_RELATION_SET_SIZE,
|
|
"<none>");
|
|
|
|
return relation_attrs[relation];
|
|
}
|
|
|
|
static const char *state_attrs[] = {
|
|
[GTK_ACCESSIBLE_STATE_BUSY] = "busy",
|
|
[GTK_ACCESSIBLE_STATE_CHECKED] = "checked",
|
|
[GTK_ACCESSIBLE_STATE_DISABLED] = "disabled",
|
|
[GTK_ACCESSIBLE_STATE_EXPANDED] = "expanded",
|
|
[GTK_ACCESSIBLE_STATE_HIDDEN] = "hidden",
|
|
[GTK_ACCESSIBLE_STATE_INVALID] = "invalid",
|
|
[GTK_ACCESSIBLE_STATE_PRESSED] = "pressed",
|
|
[GTK_ACCESSIBLE_STATE_SELECTED] = "selected",
|
|
};
|
|
|
|
/*< private >
|
|
* gtk_accessible_state_get_attribute_name:
|
|
* @state: a #GtkAccessibleState
|
|
*
|
|
* Retrieves the name of a #GtkAccessibleState.
|
|
*
|
|
* Returns: (transfer none): the name of the accessible state
|
|
*/
|
|
const char *
|
|
gtk_accessible_state_get_attribute_name (GtkAccessibleState state)
|
|
{
|
|
g_return_val_if_fail (state >= GTK_ACCESSIBLE_STATE_BUSY &&
|
|
state <= GTK_ACCESSIBLE_STATE_SELECTED,
|
|
"<none>");
|
|
|
|
return state_attrs[state];
|
|
}
|
|
|
|
static void
|
|
gtk_at_context_init (GtkATContext *self)
|
|
{
|
|
self->accessible_role = GTK_ACCESSIBLE_ROLE_NONE;
|
|
|
|
self->properties =
|
|
gtk_accessible_attribute_set_new (N_PROPERTIES,
|
|
property_attrs,
|
|
(GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_property);
|
|
self->relations =
|
|
gtk_accessible_attribute_set_new (N_RELATIONS,
|
|
relation_attrs,
|
|
(GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_relation);
|
|
self->states =
|
|
gtk_accessible_attribute_set_new (N_STATES,
|
|
state_attrs,
|
|
(GtkAccessibleAttributeDefaultFunc) gtk_accessible_value_get_default_for_state);
|
|
}
|
|
|
|
/**
|
|
* gtk_at_context_get_accessible:
|
|
* @self: a #GtkATContext
|
|
*
|
|
* Retrieves the #GtkAccessible using this context.
|
|
*
|
|
* Returns: (transfer none): a #GtkAccessible
|
|
*/
|
|
GtkAccessible *
|
|
gtk_at_context_get_accessible (GtkATContext *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
|
|
|
|
return self->accessible;
|
|
}
|
|
|
|
/**
|
|
* gtk_at_context_get_accessible_role:
|
|
* @self: a #GtkATContext
|
|
*
|
|
* Retrieves the accessible role of this context.
|
|
*
|
|
* Returns: a #GtkAccessibleRole
|
|
*/
|
|
GtkAccessibleRole
|
|
gtk_at_context_get_accessible_role (GtkATContext *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), GTK_ACCESSIBLE_ROLE_NONE);
|
|
|
|
return self->accessible_role;
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_get_display:
|
|
* @self: a #GtkATContext
|
|
*
|
|
* Retrieves the #GdkDisplay used to create the context.
|
|
*
|
|
* Returns: (transfer none): a #GdkDisplay
|
|
*/
|
|
GdkDisplay *
|
|
gtk_at_context_get_display (GtkATContext *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
|
|
|
|
return self->display;
|
|
}
|
|
|
|
static const struct {
|
|
const char *name;
|
|
GtkATContext * (* create_context) (GtkAccessibleRole accessible_role,
|
|
GtkAccessible *accessible,
|
|
GdkDisplay *display);
|
|
} a11y_backends[] = {
|
|
#if defined(GDK_WINDOWING_WAYLAND)
|
|
{ "AT-SPI (Wayland)", gtk_at_spi_create_context },
|
|
#endif
|
|
#if defined(GDK_WINDOWING_X11)
|
|
{ "AT-SPI (X11)", gtk_at_spi_create_context },
|
|
#endif
|
|
{ NULL, NULL },
|
|
};
|
|
|
|
/**
|
|
* gtk_at_context_create: (constructor)
|
|
* @accessible_role: the accessible role used by the #GtkATContext
|
|
* @accessible: the #GtkAccessible implementation using the #GtkATContext
|
|
* @display: the #GdkDisplay used by the #GtkATContext
|
|
*
|
|
* Creates a new #GtkATContext instance for the given accessible role,
|
|
* accessible instance, and display connection.
|
|
*
|
|
* The #GtkATContext implementation being instantiated will depend on the
|
|
* platform.
|
|
*
|
|
* Returns: (nullable) (transfer full): the #GtkATContext
|
|
*/
|
|
GtkATContext *
|
|
gtk_at_context_create (GtkAccessibleRole accessible_role,
|
|
GtkAccessible *accessible,
|
|
GdkDisplay *display)
|
|
{
|
|
static const char *gtk_test_accessible;
|
|
static const char *gtk_no_a11y;
|
|
|
|
if (G_UNLIKELY (gtk_test_accessible == NULL))
|
|
{
|
|
const char *env = g_getenv ("GTK_TEST_ACCESSIBLE");
|
|
|
|
if (env != NULL && *env !='\0')
|
|
gtk_test_accessible = "1";
|
|
else
|
|
gtk_test_accessible = "0";
|
|
}
|
|
|
|
if (G_UNLIKELY (gtk_no_a11y == NULL))
|
|
{
|
|
const char *env = g_getenv ("GTK_NO_A11Y");
|
|
|
|
if (env != NULL && *env != '\0')
|
|
gtk_no_a11y = "1";
|
|
else
|
|
gtk_no_a11y = "0";
|
|
}
|
|
|
|
/* Shortcut everything if we're running with the test AT context */
|
|
if (gtk_test_accessible[0] == '1')
|
|
return gtk_test_at_context_new (accessible_role, accessible);
|
|
|
|
if (gtk_no_a11y[0] == '1')
|
|
return NULL;
|
|
|
|
GtkATContext *res = NULL;
|
|
|
|
for (guint i = 0; i < G_N_ELEMENTS (a11y_backends); i++)
|
|
{
|
|
if (a11y_backends[i].name == NULL)
|
|
break;
|
|
|
|
GTK_NOTE (A11Y, g_message ("Trying %s a11y backend", a11y_backends[i].name));
|
|
if (a11y_backends[i].create_context != NULL)
|
|
{
|
|
res = a11y_backends[i].create_context (accessible_role, accessible, display);
|
|
if (res != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Fall back to the test context, so we can get debugging data */
|
|
if (res == NULL)
|
|
res = g_object_new (GTK_TYPE_TEST_AT_CONTEXT,
|
|
"accessible_role", accessible_role,
|
|
"accessible", accessible,
|
|
"display", display,
|
|
NULL);
|
|
|
|
/* FIXME: Add GIOExtension for AT contexts */
|
|
return res;
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_update:
|
|
* @self: a #GtkATContext
|
|
*
|
|
* Notifies the AT connected to this #GtkATContext that the accessible
|
|
* state and its properties have changed.
|
|
*/
|
|
void
|
|
gtk_at_context_update (GtkATContext *self)
|
|
{
|
|
g_return_if_fail (GTK_IS_AT_CONTEXT (self));
|
|
|
|
/* There's no point in notifying of state changes if there weren't any */
|
|
if (self->updated_properties == 0 &&
|
|
self->updated_relations == 0 &&
|
|
self->updated_states == 0 &&
|
|
self->updated_platform == 0)
|
|
return;
|
|
|
|
GtkAccessibleStateChange changed_states =
|
|
gtk_accessible_attribute_set_get_changed (self->states);
|
|
GtkAccessiblePropertyChange changed_properties =
|
|
gtk_accessible_attribute_set_get_changed (self->properties);
|
|
GtkAccessibleRelationChange changed_relations =
|
|
gtk_accessible_attribute_set_get_changed (self->relations);
|
|
|
|
GTK_AT_CONTEXT_GET_CLASS (self)->state_change (self,
|
|
changed_states, changed_properties, changed_relations,
|
|
self->updated_platform,
|
|
self->states, self->properties, self->relations);
|
|
g_signal_emit (self, obj_signals[STATE_CHANGE], 0);
|
|
|
|
self->updated_properties = 0;
|
|
self->updated_relations = 0;
|
|
self->updated_states = 0;
|
|
self->updated_platform = 0;
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_set_accessible_state:
|
|
* @self: a #GtkATContext
|
|
* @state: a #GtkAccessibleState
|
|
* @value: (nullable): #GtkAccessibleValue
|
|
*
|
|
* Sets the @value for the given @state of a #GtkATContext.
|
|
*
|
|
* If @value is %NULL, the state is unset.
|
|
*
|
|
* This function will accumulate state changes until gtk_at_context_update()
|
|
* is called.
|
|
*/
|
|
void
|
|
gtk_at_context_set_accessible_state (GtkATContext *self,
|
|
GtkAccessibleState state,
|
|
GtkAccessibleValue *value)
|
|
{
|
|
g_return_if_fail (GTK_IS_AT_CONTEXT (self));
|
|
|
|
gboolean res = FALSE;
|
|
|
|
if (value != NULL)
|
|
res = gtk_accessible_attribute_set_add (self->states, state, value);
|
|
else
|
|
res = gtk_accessible_attribute_set_remove (self->states, state);
|
|
|
|
if (res)
|
|
self->updated_states |= (1 << state);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_has_accessible_state:
|
|
* @self: a #GtkATContext
|
|
* @state: a #GtkAccessibleState
|
|
*
|
|
* Checks whether a #GtkATContext has the given @state set.
|
|
*
|
|
* Returns: %TRUE, if the accessible state is set
|
|
*/
|
|
gboolean
|
|
gtk_at_context_has_accessible_state (GtkATContext *self,
|
|
GtkAccessibleState state)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), FALSE);
|
|
|
|
return gtk_accessible_attribute_set_contains (self->states, state);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_get_accessible_state:
|
|
* @self: a #GtkATContext
|
|
* @state: a #GtkAccessibleState
|
|
*
|
|
* Retrieves the value for the accessible state of a #GtkATContext.
|
|
*
|
|
* Returns: (transfer none): the value for the given state
|
|
*/
|
|
GtkAccessibleValue *
|
|
gtk_at_context_get_accessible_state (GtkATContext *self,
|
|
GtkAccessibleState state)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
|
|
|
|
return gtk_accessible_attribute_set_get_value (self->states, state);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_set_accessible_property:
|
|
* @self: a #GtkATContext
|
|
* @property: a #GtkAccessibleProperty
|
|
* @value: (nullable): #GtkAccessibleValue
|
|
*
|
|
* Sets the @value for the given @property of a #GtkATContext.
|
|
*
|
|
* If @value is %NULL, the property is unset.
|
|
*
|
|
* This function will accumulate property changes until gtk_at_context_update()
|
|
* is called.
|
|
*/
|
|
void
|
|
gtk_at_context_set_accessible_property (GtkATContext *self,
|
|
GtkAccessibleProperty property,
|
|
GtkAccessibleValue *value)
|
|
{
|
|
g_return_if_fail (GTK_IS_AT_CONTEXT (self));
|
|
|
|
gboolean res = FALSE;
|
|
|
|
if (value != NULL)
|
|
res = gtk_accessible_attribute_set_add (self->properties, property, value);
|
|
else
|
|
res = gtk_accessible_attribute_set_remove (self->properties, property);
|
|
|
|
if (res)
|
|
self->updated_properties |= (1 << property);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_has_accessible_property:
|
|
* @self: a #GtkATContext
|
|
* @property: a #GtkAccessibleProperty
|
|
*
|
|
* Checks whether a #GtkATContext has the given @property set.
|
|
*
|
|
* Returns: %TRUE, if the accessible property is set
|
|
*/
|
|
gboolean
|
|
gtk_at_context_has_accessible_property (GtkATContext *self,
|
|
GtkAccessibleProperty property)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), FALSE);
|
|
|
|
return gtk_accessible_attribute_set_contains (self->properties, property);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_get_accessible_property:
|
|
* @self: a #GtkATContext
|
|
* @property: a #GtkAccessibleProperty
|
|
*
|
|
* Retrieves the value for the accessible property of a #GtkATContext.
|
|
*
|
|
* Returns: (transfer none): the value for the given property
|
|
*/
|
|
GtkAccessibleValue *
|
|
gtk_at_context_get_accessible_property (GtkATContext *self,
|
|
GtkAccessibleProperty property)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
|
|
|
|
return gtk_accessible_attribute_set_get_value (self->properties, property);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_set_accessible_relation:
|
|
* @self: a #GtkATContext
|
|
* @relation: a #GtkAccessibleRelation
|
|
* @value: (nullable): #GtkAccessibleValue
|
|
*
|
|
* Sets the @value for the given @relation of a #GtkATContext.
|
|
*
|
|
* If @value is %NULL, the relation is unset.
|
|
*
|
|
* This function will accumulate relation changes until gtk_at_context_update()
|
|
* is called.
|
|
*/
|
|
void
|
|
gtk_at_context_set_accessible_relation (GtkATContext *self,
|
|
GtkAccessibleRelation relation,
|
|
GtkAccessibleValue *value)
|
|
{
|
|
g_return_if_fail (GTK_IS_AT_CONTEXT (self));
|
|
|
|
gboolean res = FALSE;
|
|
|
|
if (value != NULL)
|
|
res = gtk_accessible_attribute_set_add (self->relations, relation, value);
|
|
else
|
|
res = gtk_accessible_attribute_set_remove (self->relations, relation);
|
|
|
|
if (res)
|
|
self->updated_relations |= (1 << relation);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_has_accessible_relation:
|
|
* @self: a #GtkATContext
|
|
* @relation: a #GtkAccessibleRelation
|
|
*
|
|
* Checks whether a #GtkATContext has the given @relation set.
|
|
*
|
|
* Returns: %TRUE, if the accessible relation is set
|
|
*/
|
|
gboolean
|
|
gtk_at_context_has_accessible_relation (GtkATContext *self,
|
|
GtkAccessibleRelation relation)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), FALSE);
|
|
|
|
return gtk_accessible_attribute_set_contains (self->relations, relation);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_get_accessible_relation:
|
|
* @self: a #GtkATContext
|
|
* @relation: a #GtkAccessibleRelation
|
|
*
|
|
* Retrieves the value for the accessible relation of a #GtkATContext.
|
|
*
|
|
* Returns: (transfer none): the value for the given relation
|
|
*/
|
|
GtkAccessibleValue *
|
|
gtk_at_context_get_accessible_relation (GtkATContext *self,
|
|
GtkAccessibleRelation relation)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
|
|
|
|
return gtk_accessible_attribute_set_get_value (self->relations, relation);
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_context_get_label:
|
|
* @self: a #GtkATContext
|
|
*
|
|
* Retrieves the accessible label of the #GtkATContext.
|
|
*
|
|
* This is a convenience function meant to be used by #GtkATContext implementations.
|
|
*
|
|
* Returns: (transfer full): the label of the #GtkATContext
|
|
*/
|
|
char *
|
|
gtk_at_context_get_label (GtkATContext *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_CONTEXT (self), NULL);
|
|
|
|
GtkAccessibleValue *value = NULL;
|
|
|
|
if (gtk_accessible_attribute_set_contains (self->states, GTK_ACCESSIBLE_STATE_HIDDEN))
|
|
{
|
|
value = gtk_accessible_attribute_set_get_value (self->states, GTK_ACCESSIBLE_STATE_HIDDEN);
|
|
|
|
if (gtk_boolean_accessible_value_get (value))
|
|
return g_strdup ("");
|
|
}
|
|
|
|
if (gtk_accessible_attribute_set_contains (self->properties, GTK_ACCESSIBLE_PROPERTY_LABEL))
|
|
{
|
|
value = gtk_accessible_attribute_set_get_value (self->properties, GTK_ACCESSIBLE_PROPERTY_LABEL);
|
|
|
|
return g_strdup (gtk_string_accessible_value_get (value));
|
|
}
|
|
|
|
if (gtk_accessible_attribute_set_contains (self->relations, GTK_ACCESSIBLE_RELATION_LABELLED_BY))
|
|
{
|
|
value = gtk_accessible_attribute_set_get_value (self->relations, GTK_ACCESSIBLE_RELATION_LABELLED_BY);
|
|
|
|
GList *list = gtk_reference_list_accessible_value_get (value);
|
|
GtkAccessible *rel = GTK_ACCESSIBLE (list->data);
|
|
GtkATContext *rel_context = gtk_accessible_get_at_context (rel);
|
|
|
|
return gtk_at_context_get_label (rel_context);
|
|
}
|
|
|
|
GtkAccessibleRole role = gtk_at_context_get_accessible_role (self);
|
|
|
|
switch ((int) role)
|
|
{
|
|
case GTK_ACCESSIBLE_ROLE_RANGE:
|
|
{
|
|
int range_attrs[] = {
|
|
GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT,
|
|
GTK_ACCESSIBLE_PROPERTY_VALUE_NOW,
|
|
};
|
|
|
|
for (int i = 0; i < G_N_ELEMENTS (range_attrs); i++)
|
|
{
|
|
if (gtk_accessible_attribute_set_contains (self->properties, range_attrs[i]))
|
|
{
|
|
value = gtk_accessible_attribute_set_get_value (self->properties, range_attrs[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (value != NULL)
|
|
return g_strdup (gtk_string_accessible_value_get (value));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GEnumClass *enum_class = g_type_class_peek (GTK_TYPE_ACCESSIBLE_ROLE);
|
|
GEnumValue *enum_value = g_enum_get_value (enum_class, role);
|
|
|
|
if (enum_value != NULL)
|
|
return g_strdup (enum_value->value_nick);
|
|
|
|
return g_strdup ("widget");
|
|
}
|
|
|
|
void
|
|
gtk_at_context_platform_changed (GtkATContext *self,
|
|
GtkAccessiblePlatformChange change)
|
|
{
|
|
self->updated_platform |= change;
|
|
}
|