Merge branch 'gtk-gtk_accessible_announce' into 'main'

a11y: Introduce an API for requesting speech from a screen reader

See merge request GNOME/gtk!6864
This commit is contained in:
Matthias Clasen 2024-02-09 05:06:02 +00:00
commit e4ec066337
7 changed files with 124 additions and 0 deletions

View File

@ -1531,6 +1531,42 @@ gtk_at_spi_context_unrealize (GtkATContext *context)
g_clear_object (&self->root);
}
static void
gtk_at_spi_context_announce (GtkATContext *context,
const char *message,
GtkAccessibleAnnouncementPriority priority)
{
GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context);
AtspiLive live;
if (self->connection == NULL)
return;
switch (priority)
{
case GTK_ACCESSIBLE_ANNOUNCEMENT_PRIORITY_LOW:
case GTK_ACCESSIBLE_ANNOUNCEMENT_PRIORITY_MEDIUM:
live = ATSPI_LIVE_POLITE;
break;
case GTK_ACCESSIBLE_ANNOUNCEMENT_PRIORITY_HIGH:
live = ATSPI_LIVE_ASSERTIVE;
break;
default:
g_assert_not_reached ();
}
g_dbus_connection_emit_signal (self->connection,
NULL,
self->context_path,
"org.a11y.atspi.Event.Object",
"Announcement",
g_variant_new ("(siiva{sv})",
"", live, 0,
g_variant_new_string (message),
NULL),
NULL);
}
static void
gtk_at_spi_context_class_init (GtkAtSpiContextClass *klass)
{
@ -1545,6 +1581,7 @@ gtk_at_spi_context_class_init (GtkAtSpiContextClass *klass)
context_class->platform_change = gtk_at_spi_context_platform_change;
context_class->bounds_change = gtk_at_spi_context_bounds_change;
context_class->child_change = gtk_at_spi_context_child_change;
context_class->announce = gtk_at_spi_context_announce;
}
static void

View File

@ -277,6 +277,11 @@ typedef enum {
ATSPI_SCROLL_ANYWHERE
} AtspiScrollType;
typedef enum {
ATSPI_LIVE_POLITE = 1,
ATSPI_LIVE_ASSERTIVE = 2
} AtspiLive;
typedef struct _GtkAtSpiRoot GtkAtSpiRoot;
typedef struct _GtkAtSpiCache GtkAtSpiCache;
typedef struct _GtkAtSpiContext GtkAtSpiContext;

View File

@ -751,6 +751,41 @@ gtk_accessible_reset_relation (GtkAccessible *self,
g_object_unref (context);
}
/**
* gtk_accessible_announce:
* @self: a `GtkAccessible`
* @message: the string to announce
* @priority: the priority of the announcement
*
* Requests the user's screen reader to announce the given message.
*
* This kind of notification is useful for messages that
* either have only a visual representation or that are not
* exposed visually at all, e.g. a notification about a
* successful operation.
*
* Also, by using this API, you can ensure that the message
* does not interrupts the user's current screen reader output.
*
* Since: 4.14
*/
void
gtk_accessible_announce (GtkAccessible *self,
const char *message,
GtkAccessibleAnnouncementPriority priority)
{
GtkATContext *context;
g_return_if_fail (GTK_IS_ACCESSIBLE (self));
context = gtk_accessible_get_at_context (self);
if (context == NULL)
return;
gtk_at_context_announce (context, message, priority);
g_object_unref (context);
}
static const char *role_names[] = {
[GTK_ACCESSIBLE_ROLE_ALERT] = NC_("accessibility", "alert"),
[GTK_ACCESSIBLE_ROLE_ALERT_DIALOG] = NC_("accessibility", "alert dialog"),

View File

@ -260,4 +260,9 @@ GDK_AVAILABLE_IN_4_14
GtkAccessibleList * gtk_accessible_list_new_from_array (GtkAccessible **accessibles,
gsize n_accessibles);
GDK_AVAILABLE_IN_4_14
void gtk_accessible_announce (GtkAccessible *self,
const char *message,
GtkAccessibleAnnouncementPriority priority);
G_END_DECLS

View File

@ -1473,3 +1473,14 @@ gtk_at_context_child_changed (GtkATContext *self,
GTK_AT_CONTEXT_GET_CLASS (self)->child_change (self, change, child);
}
void
gtk_at_context_announce (GtkATContext *self,
const char *message,
GtkAccessibleAnnouncementPriority priority)
{
if (!self->realized)
return;
GTK_AT_CONTEXT_GET_CLASS (self)->announce (self, message, priority);
}

View File

@ -127,6 +127,10 @@ struct _GtkATContextClass
void (* realize) (GtkATContext *self);
void (* unrealize) (GtkATContext *self);
void (* announce) (GtkATContext *self,
const char *message,
GtkAccessibleAnnouncementPriority priority);
};
GtkATContext * gtk_at_context_clone (GtkATContext *self,
@ -193,4 +197,8 @@ void
gtk_at_context_set_next_accessible_sibling (GtkATContext *self,
GtkAccessible *sibling);
void gtk_at_context_announce (GtkATContext *self,
const char *message,
GtkAccessibleAnnouncementPriority priority);
G_END_DECLS

View File

@ -1801,6 +1801,29 @@ typedef enum { /*< prefix=GTK_ACCESSIBLE_SORT >*/
GTK_ACCESSIBLE_SORT_OTHER
} GtkAccessibleSort;
/**
* GTK_ANNOUNCEMENT_PRIORITY:
* @GTK_ANNOUNCEMENT_PRIORITY_LOW: The announcement is low priority, and might be read only
* on the user's request.
* @GTK_ANNOUNCEMENT_PRIORITY_MEDIUM: The announcement is of medium priority, and is usually
* spoken at the next opportunity, such as at the end of speaking the current sentence
* or when the user pauses typing.
* @GTK_ANNOUNCEMENT_PRIORITY_HIGH: The announcement is of high priority, and is usually
* spoken immediately. Because an interruption might disorient users or cause them to
* not complete their current task, authors SHOULD NOT use high priority announcements
* unless the interruption is imperative. An example would be a notification about a
* critical battery power level.
*
* The priority of an accessibility announcement.
*
* Since: 4.14
*/
typedef enum {
GTK_ACCESSIBLE_ANNOUNCEMENT_PRIORITY_LOW,
GTK_ACCESSIBLE_ANNOUNCEMENT_PRIORITY_MEDIUM,
GTK_ACCESSIBLE_ANNOUNCEMENT_PRIORITY_HIGH
} GtkAccessibleAnnouncementPriority;
/**
* GtkPopoverMenuFlags:
* @GTK_POPOVER_MENU_SLIDING: Submenus are presented as sliding submenus that