[Kde-accessibility] Re: Qt Accessibility

Volker Hilsheimer vohi at trolltech.com
Wed Jul 16 12:34:29 CEST 2003


> > Hello Olaf,
> >
> > There is indeed no documented API for accessibility plugins right now.
The
> > current infrastructure still uses QCom directly (the later deprecated
API
> > introduced in the Qt 3.0 betas), which is also used in the internals
of
> > e.g. custom widgets for Qt Designer, image format plugins or SQL
drivers.
> > For those we have dedicated plugin classes that hide the nasty
details,
> > e.g. QWidgetPlugin, but the concept is the same.
> > [...]
>
> This is a point that needs to be changed IMHO. It would be good if you
could
> create an official API for providing such plug ins.

Yes, this will definitely happen. Something equivalent to QWidgetPlugin.

> > What would probably make most sense is a way to install
non-plugin-based
> > factories. This factory can then reside in the application binary
rather
> > than in a separate plugin, which makes it easier to implement
> > QAccessibleInterface for custom widget.
>
> That sounds reasonable. I only suspect that it might be harder to tell
people
> `write a factory' than to say `implement a method'.

If we add a new virtual method is something we can discuss here, but
factories are pretty trivial to document and implement.

> > Moving the QAccessibleWidget
> > helper class into the Qt API will probably be a good idea.
>
> Definitely. Maybe it should also be possible to get the accessibility
> implementation for the parent class type (for internal use) if you
extend a
> given widget and only need to add one little detail to the accessibility
> information?

The following is already done in QAccessible::queryAccessibleInterface:

 QMetaObject *mo = object->metaObject();
 while ( mo ) {
     qAccessibleManager->queryInterface( mo->className(), &factory );
     if ( factory )
        break;
     mo = mo->superClass();
}
if ( factory )
    return factory->createAccessibleInterface( mo->className(), object,
iface );

So worst case right now is that you get accessibility information for
QWidget if you want it for a completely custom widget (this will at least
allow you to navigate). For a simple subclass of QPushButton that
reimplements sizeHint() or whatever you don't have to do anything.

To change an existing interface you can of course use
QAccessible::queryAccessibleInterface to get an interface for the class
you want, and then use containment.

> > What would be important for us to know is how Qt can communicate with
the
> > AT-SPI bridge. How does the Qt application get notified that it is
> > supposed to provide a QAccessibleInterface, how does Qt pass that
> > QAccessibleInterface to the bridge library, and how does Qt pass
> > notifications on to the bridge.
>
> In AT-SPI the application needs to register with the accessibility
broker
> (also called registry) once it has started. The registry then calls a
method
> of the application to enquire the root accessible object. From this
object
> all other accessible objects need to be reachable by
> parent-child-relationships. (I would guess that the windows of the
> application are the children of the root accessible object). The
notification
> is done by calling a method on the registry for every single event that
> occurs. I would say that we could do similar things for the interface
between
> Qt and the accessibility bridge.

Hm, what happens if the first AT client is started after the application
(ie. no broker yet)? Does a running broker imply a running AT client?
Otherwise, how do you find out if accessibility updates are necessary
(they can be rather expensive for e.g. listviews).

In Qt, the root accessible object would be an QAccessibleInterface for
QApplication. The children would be what QApplication::topLevelWidgets()
returns (probably with some exceptions, e.g. no tooltips, no popup menus
etc).

> > As discussed on the web, a solution that introduces no dependencies to
Qt
> > would obviously be the best. Hence I guess a shared library with a
defined
> > name and C-API would be the best (since the bridge would only work on
the
> > pure-virtual QAccessibleInterface it wouldn't even have to link
against
> > Qt, and only bootstrap some classes used by the API, e.g. QString,
QRect
> > and QMemArray; linking the bridge against Qt would however not be a
> > problem).
> >
> > Qt could then try to dlopen that library when the first request comes
in
> > through the event loop (at this point, QAccessible::isActive() returns
> > TRUE if the library could be loaded), and resolve two basic functions
from
> > that shared library:
>
> That sounds similar to the plug-in approach discused on the web pages,
only
> that the loading mechanism gets simplified and is no longer flexible.
> However, it does not need to be flexible if the bridge is the only `plug
in'
> for the given interface.

A plugin approach implies that multiple plugins can be installed. After
reading Maks' mails I'm not sure if this is what is meant with "just make
QAccessible broadcast ::updateAccessible to the loaded plugin". A plugin
approach also requires a predefined interface between Qt and the plugin,
and of course a plugin has zero chance to control if Qt uses it or not.

A single library with a given name and API makes most sense IMHO. If you
don't like the implementation you can still use a different library (and
this *could* be configurable through e.g. qtrc).

> > - ProvideAccessibleObject( QAccessibleInterface *iface, int
requestID )
>
> I don't get what you mean with this method. As far as I understood it is
> sufficient if the bridge provides a function
>
> initialize (QAccessibleInterface *root)
>
> The only parameter of this function is the root accessible object of the
> application. All information of the other objects can then be reached by
> parent-child relationships.

Yep, you're right, this will be enough.

> > - NotifyAccessibilityUpdate(QAccessible::Event, WinID window, int
childID)
> > This function would be used in the Unix implementation of
> > QAccessible::updateAccessibility()
>
> I would use the signature
>
> NotifyAccessibilityUpdate(QAccessible::Event, QAccessibleInterface
*iface, int
> childID)
>
> That way the bridge does only need to cope with QAccessibleInterface
objects.
> Of course that implies that there is always only one
QAccessibleInterface
> object for each given QObject.

That should be ok - queryAccessibleInterface caches QAccessibleInterfaces
already.

> > Does this make sense to you? Are more callbacks required to handle
e.g.
> > IPC?
>
> If the bridge needs to do things independently of the application, e.g.
for
> IPC, I would suggest that it internally creates a new thread when the
> initialize (...) function is called. Of course that would imply that Qt
gets
> compiled thread-safe. If that is too much a requirement then I have to
look
> into which IPC protocol we will be using in order to tell which
callbacks are
> needed.

Note that you cannot call QAccessibleInterface at all from the non-GUI
thread, as you would then be able to call property setters in GUI objects
(ie. right now via setText, or doDefaultAction). So if the bridge starts a
thread for IPC it will then have to translate the incoming calls to
QApplication::postEvent, and wait for the GUI thread to process the event
(through a wait condition). That would be pretty straight forward, and
requiring a threaded Qt support should not be an issue.

Cheers,
Volker



More information about the kde-accessibility mailing list