atcontext: Always realize non-widget accessibles

Upon joining the a11y tree. And do so recursively, as long as the parent
is also not a widget.

As for the explanation, please grab a mug of your favorite drink. It's
a little complicated.

GTK realizes AT contexts in 3 situations:

 1. When it's a toplevel, it's realized unconditionally
 2. When the widget is focused
 3. When the accessible is appended to a realized parent

Most importantly, GTK lazily realizes accessibles, and does not realize
child accessibles recursively.

Clearly, conditions 1 and 2 only ever happen for GtkWidgets, which are
accessible objects themselves. These two conditions will handle the vast
majority of cases of apps and platform libraries.

However, there are non-widget accessibles out there. GTK itself offers a
non-widget accessible implementation - GtkAtspiSocket - which is used by
WebKitGTK.

Now, let's look at WebKitGTK use case. It'll demonstrate the problem
nicely.

WebKitGTK creates the GtkAtspiSocket object *after* loading most of the
page. At this point, there are 2 possibilities:

 1. The web view widget is focused. In this case, the AT context of the
    web view is realized, and GTK will realize the GtkAtspiSocket when
    it is added to the a11y tree (condition 3 above).

 2. The web view widget is *not* focused. At some point the user focuses
    the web view, and GTK will realize the AT context of the web view.
    But remember, GTK does not realize child accessibles! That means
    GtkAtspiSocket won't be realized.

This example demonstrates a general problem with non-widget accessibles:
non-widget accessibles cannot trigger conditions 1 and 2, so they're
never realized. The only way they're realized in if they happen to be
added to an already realized accessible (condition 3).

To fix that, the following is proposed: always realize non-widget
accessibles, and also of their non-widget accessible parents. This is
not ideal, of course, as it might generate some D-Bus chattery, but GTK
does not have enough information to realize these objects at more
appropriate times.
This commit is contained in:
Georges Basile Stavracas Neto 2024-10-02 14:55:14 -03:00
parent 5d5b612630
commit 6074a18e3e

View File

@ -515,12 +515,29 @@ static GtkATContext * get_parent_context (GtkATContext *self);
static inline void
maybe_realize_context (GtkATContext *self)
{
GtkATContext *parent_context = get_parent_context (self);
GtkAccessible *accessible_parent;
GtkATContext *parent_context;
if (parent_context && parent_context->realized)
parent_context = get_parent_context (self);
if (!GTK_IS_WIDGET (self->accessible) || (parent_context && parent_context->realized))
gtk_at_context_realize (self);
g_clear_object (&parent_context);
accessible_parent = self->accessible_parent;
while (accessible_parent && !GTK_IS_WIDGET (accessible_parent))
{
parent_context = gtk_accessible_get_at_context (accessible_parent);
if (!parent_context)
break;
gtk_at_context_realize (parent_context);
accessible_parent = parent_context->accessible_parent;
g_clear_object (&parent_context);
}
}
/*< private >