diff --git a/gtk/a11y/gtkatspicontext.c b/gtk/a11y/gtkatspicontext.c
new file mode 100644
index 0000000000..95fc342917
--- /dev/null
+++ b/gtk/a11y/gtkatspicontext.c
@@ -0,0 +1,85 @@
+/* gtkatspicontext.c: AT-SPI GtkATContext implementation
+ *
+ * Copyright 2020 GNOME Foundation
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see .
+ */
+
+#include "config.h"
+
+#include "gtkatspicontextprivate.h"
+
+struct _GtkAtSpiContext
+{
+ GtkATContext parent_instance;
+};
+
+G_DEFINE_TYPE (GtkAtSpiContext, gtk_at_spi_context, GTK_TYPE_AT_CONTEXT)
+
+static void
+gtk_at_spi_context_state_change (GtkATContext *self,
+ GtkAccessibleStateChange changed_states,
+ GtkAccessiblePropertyChange changed_properties,
+ GtkAccessibleRelationChange changed_relations,
+ GtkAccessibleAttributeSet *states,
+ GtkAccessibleAttributeSet *properties,
+ GtkAccessibleAttributeSet *relations)
+{
+}
+
+static void
+gtk_at_spi_context_constructed (GObject *gobject)
+{
+ G_OBJECT_CLASS (gtk_at_spi_context_parent_class)->constructed (gobject);
+}
+
+static void
+gtk_at_spi_context_class_init (GtkAtSpiContextClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkATContextClass *context_class = GTK_AT_CONTEXT_CLASS (klass);
+
+ gobject_class->constructed = gtk_at_spi_context_constructed;
+
+ context_class->state_change = gtk_at_spi_context_state_change;
+}
+
+static void
+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)
+{
+ g_return_val_if_fail (GTK_IS_ACCESSIBLE (accessible), NULL);
+
+ return g_object_new (GTK_TYPE_AT_SPI_CONTEXT,
+ "accessible-role", accessible_role,
+ "accessible", accessible,
+ NULL);
+}
diff --git a/gtk/a11y/gtkatspicontextprivate.h b/gtk/a11y/gtkatspicontextprivate.h
new file mode 100644
index 0000000000..28205f1fbc
--- /dev/null
+++ b/gtk/a11y/gtkatspicontextprivate.h
@@ -0,0 +1,35 @@
+/* gtkatspicontextprivate.h: AT-SPI GtkATContext implementation
+ *
+ * Copyright 2020 GNOME Foundation
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see .
+ */
+
+#pragma once
+
+#include "gtkatcontextprivate.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_AT_SPI_CONTEXT (gtk_at_spi_context_get_type())
+
+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);
+
+G_END_DECLS
diff --git a/gtk/a11y/meson.build b/gtk/a11y/meson.build
index b3555eff27..22d1956027 100644
--- a/gtk/a11y/meson.build
+++ b/gtk/a11y/meson.build
@@ -7,4 +7,8 @@ endif
if gtk_a11y_backends.contains('atspi')
subdir('atspi')
+
+ gtk_a11y_src += files([
+ 'gtkatspicontext.c',
+ ])
endif
diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c
index 6686e3f9a9..4d86a2346d 100644
--- a/gtk/gtkatcontext.c
+++ b/gtk/gtkatcontext.c
@@ -36,9 +36,14 @@
#include "gtkatcontextprivate.h"
#include "gtkaccessiblevalueprivate.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
@@ -354,6 +359,20 @@ gtk_at_context_get_accessible_role (GtkATContext *self)
return self->accessible_role;
}
+static const struct {
+ const char *name;
+ GtkATContext * (* create_context) (GtkAccessibleRole accessible_role,
+ GtkAccessible *accessible);
+} a11y_backends[] = {
+#if defined(GDK_WINDOWING_WAYLAND)
+ { "AT-SPI", _gtk_at_spi_context_new },
+#endif
+#if defined(GDK_WINDOWING_X11)
+ { "AT-SPI", gtk_at_spi_context_new },
+#endif
+ { NULL, NULL },
+};
+
/**
* gtk_at_context_create: (constructor)
* @accessible_role: the accessible role used by the #GtkATContext
@@ -401,8 +420,23 @@ gtk_at_context_create (GtkAccessibleRole accessible_role,
if (gtk_no_a11y[0] == '1')
return NULL;
+ GtkATContext *res = NULL;
+
+ for (guint i = 0; i < G_N_ELEMENTS (a11y_backends); i++)
+ {
+ 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;
+ }
+ }
+
+ if (res == NULL)
+ res = gtk_test_at_context_new (accessible_role, accessible);
+
/* FIXME: Add GIOExtension for AT contexts */
- return gtk_test_at_context_new (accessible_role, accessible);
+ return res;
}
/*< private >