summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/accessible/qaccessible_win.cpp34
-rw-r--r--tests/auto/qaccessibility/tst_qaccessibility.cpp8
2 files changed, 32 insertions, 10 deletions
diff --git a/src/gui/accessible/qaccessible_win.cpp b/src/gui/accessible/qaccessible_win.cpp
index 678a528..f9f9f04 100644
--- a/src/gui/accessible/qaccessible_win.cpp
+++ b/src/gui/accessible/qaccessible_win.cpp
@@ -49,6 +49,7 @@
#include "qsettings.h"
#include <QtCore/qmap.h>
#include <QtCore/qpair.h>
+#include <QtCore/qpointer.h>
#include <QtGui/qgraphicsitem.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
@@ -265,7 +266,7 @@ void showDebug(const char* funcName, const QAccessibleInterface *iface)
#endif
// This stuff is used for widgets/items with no window handle:
-typedef QMap<int, QPair<QObject*,int> > NotifyMap;
+typedef QMap<int, QPair<QPointer<QObject>, int> > NotifyMap;
Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
static int eventNum = 0;
@@ -414,13 +415,26 @@ void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
if (reason != MenuCommand) { // MenuCommand is faked
if (w != o) {
// See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
- eventNum %= 50; //[0..49]
- int eventId = - eventNum - 1;
-
- qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o,who));
- ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, eventId );
-
- ++eventNum;
+ if (reason != QAccessible::ObjectDestroyed) {
+ /* In some rare occasions, the server (Qt) might get a ::get_accChild call with a
+ childId that references an entry in the cache where there was a dangling
+ QObject-pointer. Previously we crashed on this.
+
+ There is no point in actually notifying the AT client that the object got destroyed,
+ because the AT client won't query for get_accChild if the event is ObjectDestroyed
+ anyway, and we have no other way of mapping the eventId argument to the actual
+ child/descendant object. (Firefox seems to simply completely ignore
+ EVENT_OBJECT_DESTROY).
+
+ We therefore guard each QObject in the cache with a QPointer, and only notify the AT
+ client if the type is not ObjectDestroyed.
+ */
+ eventNum %= 50; //[0..49]
+ int eventId = - eventNum - 1;
+ qAccessibleRecentSentEvents()->insert(eventId, qMakePair(QPointer<QObject>(o), who));
+ ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, eventId );
+ ++eventNum;
+ }
} else {
ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, who);
}
@@ -603,8 +617,8 @@ HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
struct AccessibleElement {
AccessibleElement(int entryId, QAccessibleInterface *accessible) {
if (entryId < 0) {
- QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entryId);
- iface = QAccessible::queryAccessibleInterface(ref.first);
+ QPair<QPointer<QObject>, int> ref = qAccessibleRecentSentEvents()->value(entryId);
+ iface = QAccessible::queryAccessibleInterface(ref.first.data());
entry = ref.second;
cleanupInterface = true;
} else {
diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp
index d47eb06..39207ec 100644
--- a/tests/auto/qaccessibility/tst_qaccessibility.cpp
+++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp
@@ -436,7 +436,15 @@ void tst_QAccessibility::eventTest()
button->hide();
QVERIFY_EVENT(button, 0, QAccessible::ObjectHide);
+ // Destroy a visible widget
+ QTestAccessibility::clearEvents();
+ button->show();
+ QVERIFY_EVENT(button, 0, QAccessible::ObjectShow);
+
delete button;
+
+ QVERIFY_EVENT(button, 0, QAccessible::ObjectHide);
+ QVERIFY_EVENT(button, 0, QAccessible::ObjectDestroyed);
}
void tst_QAccessibility::customWidget()