a11y: Get event listeners on root registration

We ask the AT-SPI registry for event listeners already registered when
connecting the root object, in case an AT is running.
This commit is contained in:
Emmanuele Bassi 2024-05-25 00:53:42 +01:00
parent 307efe2172
commit d9f75581be

View File

@ -486,66 +486,6 @@ gtk_at_spi_root_child_changed (GtkAtSpiRoot *self,
window_ref);
}
typedef struct {
GtkAtSpiRoot *root;
GtkAtSpiRootRegisterFunc register_func;
} RegistrationData;
static void
on_registration_reply (GObject *gobject,
GAsyncResult *result,
gpointer user_data)
{
RegistrationData *data = user_data;
GtkAtSpiRoot *self = data->root;
GError *error = NULL;
GVariant *reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (gobject), result, &error);
self->register_id = 0;
if (error != NULL)
{
g_critical ("Unable to register the application: %s", error->message);
g_error_free (error);
return;
}
if (reply != NULL)
{
g_variant_get (reply, "((so))",
&self->desktop_name,
&self->desktop_path);
g_variant_unref (reply);
GTK_DEBUG (A11Y, "Connected to the a11y registry at (%s, %s)",
self->desktop_name,
self->desktop_path);
}
/* Register the cache object */
self->cache = gtk_at_spi_cache_new (self->connection, ATSPI_CACHE_PATH, self);
/* Drain the list of queued GtkAtSpiContexts, and add them to the cache */
if (self->queued_contexts != NULL)
{
self->queued_contexts = g_list_reverse (self->queued_contexts);
for (GList *l = self->queued_contexts; l != NULL; l = l->next)
{
if (data->register_func != NULL)
data->register_func (self, l->data);
gtk_at_spi_cache_add_context (self->cache, l->data);
}
g_clear_pointer (&self->queued_contexts, g_list_free);
}
self->toplevels = gtk_window_get_toplevels ();
g_free (data);
}
static void
on_event_listener_registered (GDBusConnection *connection,
const char *sender_name,
@ -621,6 +561,143 @@ on_event_listener_deregistered (GDBusConnection *connection,
}
}
static void
on_registered_events_reply (GObject *gobject,
GAsyncResult *result,
gpointer data)
{
GError *error = NULL;
GVariant *reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (gobject), result, &error);
if (error != NULL)
{
g_critical ("Unable to get the list of registered event listeners: %s", error->message);
g_error_free (error);
return;
}
GtkAtSpiRoot *self = data;
GVariant *listeners = g_variant_get_child_value (reply, 0);
GVariantIter *iter;
const char *sender, *event_name;
if (self->event_listeners == NULL)
self->event_listeners = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_variant_get (listeners, "a(ss)", &iter);
while (g_variant_iter_loop (iter, "(&s&s)", &sender, &event_name))
{
GTK_DEBUG (A11Y, "Registering event listener (%s, %s) on the a11y bus",
sender,
event_name[0] != 0 ? event_name : "(none)");
if (!g_hash_table_contains (self->event_listeners, sender))
g_hash_table_add (self->event_listeners, g_strdup (sender));
}
g_variant_iter_free (iter);
g_variant_unref (listeners);
g_variant_unref (reply);
}
typedef struct {
GtkAtSpiRoot *root;
GtkAtSpiRootRegisterFunc register_func;
} RegistrationData;
static void
on_registration_reply (GObject *gobject,
GAsyncResult *result,
gpointer user_data)
{
RegistrationData *data = user_data;
GtkAtSpiRoot *self = data->root;
GError *error = NULL;
GVariant *reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (gobject), result, &error);
self->register_id = 0;
if (error != NULL)
{
g_critical ("Unable to register the application: %s", error->message);
g_error_free (error);
return;
}
if (reply != NULL)
{
g_variant_get (reply, "((so))",
&self->desktop_name,
&self->desktop_path);
g_variant_unref (reply);
GTK_DEBUG (A11Y, "Connected to the a11y registry at (%s, %s)",
self->desktop_name,
self->desktop_path);
}
/* Register the cache object */
self->cache = gtk_at_spi_cache_new (self->connection, ATSPI_CACHE_PATH, self);
/* Drain the list of queued GtkAtSpiContexts, and add them to the cache */
if (self->queued_contexts != NULL)
{
self->queued_contexts = g_list_reverse (self->queued_contexts);
for (GList *l = self->queued_contexts; l != NULL; l = l->next)
{
if (data->register_func != NULL)
data->register_func (self, l->data);
gtk_at_spi_cache_add_context (self->cache, l->data);
}
g_clear_pointer (&self->queued_contexts, g_list_free);
}
self->toplevels = gtk_window_get_toplevels ();
g_free (data);
/* Subscribe to notifications on the registered event listeners */
g_dbus_connection_signal_subscribe (self->connection,
"org.a11y.atspi.Registry",
"org.a11y.atspi.Registry",
"EventListenerRegistered",
ATSPI_REGISTRY_PATH,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_event_listener_registered,
self,
NULL);
g_dbus_connection_signal_subscribe (self->connection,
"org.a11y.atspi.Registry",
"org.a11y.atspi.Registry",
"EventListenerDeregistered",
ATSPI_REGISTRY_PATH,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_event_listener_deregistered,
self,
NULL);
/* Get the list of ATs listening to events, in case they were started
* before the application; we want to delay the D-Bus traffic as much
* as possible until we know something is listening on the accessibility
* bus
*/
g_dbus_connection_call (self->connection,
"org.a11y.atspi.Registry",
ATSPI_REGISTRY_PATH,
"org.a11y.atspi.Registry",
"GetRegisteredEvents",
g_variant_new ("()"),
G_VARIANT_TYPE ("(a(ss))"),
G_DBUS_CALL_FLAGS_NONE, -1,
NULL,
on_registered_events_reply,
self);
}
static gboolean
root_register (gpointer user_data)
{
@ -667,27 +744,6 @@ root_register (gpointer user_data)
NULL,
NULL);
g_dbus_connection_signal_subscribe (self->connection,
"org.a11y.atspi.Registry",
"org.a11y.atspi.Registry",
"EventListenerRegistered",
ATSPI_REGISTRY_PATH,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_event_listener_registered,
self,
NULL);
g_dbus_connection_signal_subscribe (self->connection,
"org.a11y.atspi.Registry",
"org.a11y.atspi.Registry",
"EventListenerDeregistered",
ATSPI_REGISTRY_PATH,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_event_listener_deregistered,
self,
NULL);
GTK_DEBUG (A11Y, "Registering (%s, %s) on the a11y bus",
unique_name,
self->root_path);