a11y: Add a display to GtkATContext

Since we need to check at run time what kind of AT context to use, we
need a hook into the whole GDK backend machinery. The display connection
seems to be the best choice, in this case, as it allows us to determine
whether we're running on an X11 or Wayland system, and thus whether we
should create a GtkAtSpiContext.

This requires some surgery to fix the GtkATContext creation function, in
order to include a GdkDisplay instance.
This commit is contained in:
Emmanuele Bassi 2020-09-29 18:40:44 +01:00
parent 8f19bb0832
commit 8c18480092
7 changed files with 102 additions and 30 deletions

View File

@ -22,6 +22,13 @@
#include "gtkatspicontextprivate.h"
#if defined(GDK_WINDOWING_WAYLAND)
# include <gdk/wayland/gdkwaylanddisplay.h>
#endif
#if defined(GDK_WINDOWING_X11)
# include <gdk/x11/gdkx11display.h>
#endif
struct _GtkAtSpiContext
{
GtkATContext parent_instance;
@ -62,24 +69,30 @@ gtk_at_spi_context_init (GtkAtSpiContext *self)
{
}
/*< private >
* gtk_at_spi_context_new:
* @accessible_role: the accessible role for the AT context
* @accessible: the #GtkAccessible instance which owns the context
*
* Creates a new #GtkAtSpiContext instance for @accessible, using the
* given @accessible_role.
*
* Returns: (transfer full): the newly created #GtkAtSpiContext
*/
GtkATContext *
gtk_at_spi_context_new (GtkAccessibleRole accessible_role,
GtkAccessible * accessible)
gtk_at_spi_create_context (GtkAccessibleRole accessible_role,
GtkAccessible *accessible,
GdkDisplay *display)
{
g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), NULL);
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
"accessible-role", accessible_role,
"accessible", accessible,
NULL);
#if defined(GDK_WINDOWING_WAYLAND)
if (GDK_IS_WAYLAND_DISPLAY (display))
return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
"accessible-role", accessible_role,
"accessible", accessible,
"display", display,
NULL);
#endif
#if defined(GDK_WINDOWING_X11)
if (GDK_IS_X11_DISPLAY (display))
return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
"accessible-role", accessible_role,
"accessible", accessible,
"display", display,
NULL);
#endif
return NULL;
}

View File

@ -29,7 +29,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GtkAtSpiContext, gtk_at_spi_context, GTK, AT_SPI_CONTEXT, GtkATContext)
GtkATContext *
gtk_at_spi_context_new (GtkAccessibleRole accessible_role,
GtkAccessible *accessible);
gtk_at_spi_create_context (GtkAccessibleRole accessible_role,
GtkAccessible *accessible,
GdkDisplay *display);
G_END_DECLS

View File

@ -50,6 +50,7 @@ enum
{
PROP_ACCESSIBLE_ROLE = 1,
PROP_ACCESSIBLE,
PROP_DISPLAY,
N_PROPS
};
@ -95,6 +96,10 @@ gtk_at_context_set_property (GObject *gobject,
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);
}
@ -118,6 +123,10 @@ gtk_at_context_get_property (GObject *gobject,
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);
}
@ -177,6 +186,20 @@ gtk_at_context_class_init (GtkATContextClass *klass)
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
@ -359,16 +382,33 @@ gtk_at_context_get_accessible_role (GtkATContext *self)
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);
GtkAccessible *accessible,
GdkDisplay *display);
} a11y_backends[] = {
#if defined(GDK_WINDOWING_WAYLAND)
{ "AT-SPI", _gtk_at_spi_context_new },
{ "AT-SPI (Wayland)", gtk_at_spi_create_context },
#endif
#if defined(GDK_WINDOWING_X11)
{ "AT-SPI", gtk_at_spi_context_new },
{ "AT-SPI (X11)", gtk_at_spi_create_context },
#endif
{ NULL, NULL },
};
@ -377,9 +417,10 @@ static const struct {
* 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 and
* accessible instance.
* 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.
@ -388,7 +429,8 @@ static const struct {
*/
GtkATContext *
gtk_at_context_create (GtkAccessibleRole accessible_role,
GtkAccessible *accessible)
GtkAccessible *accessible,
GdkDisplay *display)
{
static const char *gtk_test_accessible;
static const char *gtk_no_a11y;
@ -424,16 +466,25 @@ gtk_at_context_create (GtkAccessibleRole accessible_role,
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);
break;
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 = gtk_test_at_context_new (accessible_role, accessible);
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;

View File

@ -42,6 +42,7 @@ GtkAccessibleRole gtk_at_context_get_accessible_role (GtkATContext
GDK_AVAILABLE_IN_ALL
GtkATContext * gtk_at_context_create (GtkAccessibleRole accessible_role,
GtkAccessible *accessible);
GtkAccessible *accessible,
GdkDisplay *display);
G_END_DECLS

View File

@ -86,6 +86,7 @@ struct _GtkATContext
GtkAccessibleRole accessible_role;
GtkAccessible *accessible;
GdkDisplay *display;
GtkAccessibleAttributeSet *states;
GtkAccessibleAttributeSet *properties;
@ -109,6 +110,8 @@ struct _GtkATContextClass
GtkAccessibleAttributeSet *relations);
};
GdkDisplay * gtk_at_context_get_display (GtkATContext *self);
void gtk_at_context_update (GtkATContext *self);
void gtk_at_context_set_accessible_state (GtkATContext *self,

View File

@ -8095,6 +8095,7 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
{
GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (self);
GtkWidgetClassPrivate *class_priv = widget_class->priv;
GdkDisplay *display = _gtk_widget_get_display (self);
GtkAccessibleRole role;
/* Widgets have two options to set the accessible role: either they
@ -8111,7 +8112,7 @@ gtk_widget_accessible_get_at_context (GtkAccessible *accessible)
role = class_priv->accessible_role;
priv->accessible_role = role;
priv->at_context = gtk_at_context_create (role, accessible);
priv->at_context = gtk_at_context_create (role, accessible, display);
}
return priv->at_context;

View File

@ -29,7 +29,9 @@ test_object_accessible_get_at_context (GtkAccessible *accessible)
TestObject *self = (TestObject*)accessible;
if (self->at_context == NULL)
self->at_context = gtk_at_context_create (self->role, accessible);
self->at_context = gtk_at_context_create (self->role,
accessible,
gdk_display_get_default ());
return self->at_context;
}