diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-01-03 17:18:40 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-04-02 14:32:25 +0200 |
commit | b2ec0da95641d9cec006fa9699e6d082ad35db0b (patch) | |
tree | c6ceef7e1527b98f3eda33b6e525d65ee1d810a6 /src/gui/accessible/qaccessible.cpp | |
parent | 8dfe1385b5f05b7242802a72897258a63af1ca1d (diff) |
Cache QAccessibleInterfaces.
Since there already is a one-to-one relationship
between QObject and QAccessibleInterface it makes
little sense to create and destroy the interfaces
on each call to queryAccessibleInterface.
Add a cache and keep created interfaces around for
the lifetime of the corresponding QObject.
This changes the memory management rules: accessible
interfaces must no longer be deleted. If you get an
QAccessibleIntrface pointer that pointer will stay
valid as long as the corresponding QObject is not
deleted.
This also re-enables accessibility for Mac.
We limit the range of the IDs so that they are
useable for Windows directly.
That means we can get rid of the event cache there.
This is based on: Iebf2f374916fc70a9dd29e95f45a6444b85f6cee
Change-Id: I9fe6531812c0dbc5b41101ac05830a6dd75e13a3
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
Diffstat (limited to 'src/gui/accessible/qaccessible.cpp')
-rw-r--r-- | src/gui/accessible/qaccessible.cpp | 106 |
1 files changed, 94 insertions, 12 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index 3468ebc8a7..e007c9967e 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -41,6 +41,8 @@ #include "qaccessible.h" +#include "qaccessible2_p.h" +#include "qaccessiblecache_p.h" #include "qaccessibleplugin.h" #include "qaccessibleobject.h" #include "qaccessiblebridge.h" @@ -558,6 +560,8 @@ QAccessible::RootObjectHandler QAccessible::installRootObjectHandler(RootObjectH return old; } +Q_GLOBAL_STATIC(QAccessibleCache, qAccessibleCache) + /*! If a QAccessibleInterface implementation exists for the given \a object, this function returns a pointer to the implementation; otherwise it @@ -574,8 +578,7 @@ QAccessible::RootObjectHandler QAccessible::installRootObjectHandler(RootObjectH function tries to find an implementation for the object's parent class, using the above strategy. - \warning The caller is responsible for deleting the returned - interface after use. + All interfaces are managed by an internal cache and should not be deleted. */ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) { @@ -583,6 +586,9 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) if (!object) return 0; + if (Id id = qAccessibleCache->objectToId.value(object)) + return qAccessibleCache->interfaceForId(id); + // Create a QAccessibleInterface for the object class. Start by the most // derived class and walk up the class hierarchy. const QMetaObject *mo = object->metaObject(); @@ -592,8 +598,11 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) // Check if the class has a InterfaceFactory installed. for (int i = qAccessibleFactories()->count(); i > 0; --i) { InterfaceFactory factory = qAccessibleFactories()->at(i - 1); - if (QAccessibleInterface *iface = factory(cn, object)) + if (QAccessibleInterface *iface = factory(cn, object)) { + qAccessibleCache->insert(object, iface); + Q_ASSERT(qAccessibleCache->objectToId.contains(object)); return iface; + } } #ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_LIBRARY @@ -610,22 +619,84 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) // At this point the cache should contain a valid factory pointer or 0: Q_ASSERT(qAccessiblePlugins()->contains(cn)); QAccessiblePlugin *factory = qAccessiblePlugins()->value(cn); - if (factory) - return factory->create(cn, object); + if (factory) { + QAccessibleInterface *result = factory->create(cn, object); + if (result) { // Need this condition because of QDesktopScreenWidget + qAccessibleCache->insert(object, result); + Q_ASSERT(qAccessibleCache->objectToId.contains(object)); + } + return result; + } #endif #endif mo = mo->superClass(); } #ifndef QT_NO_ACCESSIBILITY - if (object == qApp) - return new QAccessibleApplication; + if (object == qApp) { + QAccessibleInterface *appInterface = new QAccessibleApplication; + qAccessibleCache->insert(object, appInterface); + Q_ASSERT(qAccessibleCache->objectToId.contains(qApp)); + return appInterface; + } #endif return 0; } /*! + \internal + Required to ensure that manually created interfaces + are properly memory managed. + + Must only be called exactly once per interface. + This is implicitly called when calling queryAccessibleInterface, + so it's only required when re-implementing for example + the child function and returning the child after new-ing + a QAccessibleInterface subclass. + */ +QAccessible::Id QAccessible::registerAccessibleInterface(QAccessibleInterface *iface) +{ + Q_ASSERT(iface); + return qAccessibleCache->insert(iface->object(), iface); +} + +/*! + \internal + Removes the interface belonging to this id from the cache and + deletes it. The id becomes invalid an may be re-used by the + cache. +*/ +void QAccessible::deleteAccessibleInterface(Id id) +{ + qAccessibleCache->deleteInterface(id); +} + +/*! + \internal + Returns the unique ID for the accessibleInterface. +*/ +QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface) +{ + Id id = qAccessibleCache->idToInterface.key(iface); + if (!id) + id = registerAccessibleInterface(iface); + return id; +} + +/*! + \internal + Returns the QAccessibleInterface belonging to the id. + + Returns 0 if the id is invalid. +*/ +QAccessibleInterface *QAccessible::accessibleInterface(Id id) +{ + return qAccessibleCache->idToInterface.value(id); +} + + +/*! Returns true if an accessibility implementation has been requested during the runtime of the application; otherwise returns false. @@ -687,15 +758,23 @@ void QAccessible::setRootObject(QObject *object) */ void QAccessible::updateAccessibility(QAccessibleEvent *event) { - if (updateHandler) { - updateHandler(event); + if (!isActive()) return; + +#ifndef QT_NO_ACCESSIBILITY + if (event->type() == QAccessible::TableModelChanged) { + Q_ASSERT(event->object()); + if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(event->object())) { + if (iface->tableInterface()) + iface->tableInterface()->modelChange(static_cast<QAccessibleTableModelChangeEvent*>(event)); + } } - if (!isActive()) + if (updateHandler) { + updateHandler(event); return; + } -#ifndef QT_NO_ACCESSIBILITY if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) pfAccessibility->notifyAccessibilityUpdate(event); #endif @@ -1028,6 +1107,10 @@ QColor QAccessibleInterface::backgroundColor() const return QColor(); } +QAccessibleInterface::~QAccessibleInterface() +{ +} + /*! \fn QAccessibleTextInterface *QAccessibleInterface::textInterface() \internal @@ -1362,7 +1445,6 @@ QAccessibleInterface *QAccessibleEvent::accessibleInterface() const if (m_child >= 0) { QAccessibleInterface *child = iface->child(m_child); if (child) { - delete iface; iface = child; } else { qWarning() << "Cannot creat accessible child interface for object: " << m_object << " index: " << m_child; |