AXObserverRemoveNotification sometimes painfully slow [Follow up to] Hidden Cocoa apps have empty kAXWindowsAttribute
AXObserverRemoveNotification sometimes painfully slow [Follow up to] Hidden Cocoa apps have empty kAXWindowsAttribute
- Subject: AXObserverRemoveNotification sometimes painfully slow [Follow up to] Hidden Cocoa apps have empty kAXWindowsAttribute
- From: Matt Gough <email@hidden>
- Date: Wed, 26 Mar 2003 12:55:25 +0000
From - "Hidden Cocoa apps have empty kAXWindowsAttribute"
John Louch said:
>
Note, if you're holding onto a AXUIElementRef to a window when you hide
>
a Cocoa app, you get a destroyed notification. It's gone as far as
>
accessibility is concerned.
and from - "Various AXObserver questions"
I said:
>
> 3. I assume that AXObserverRemoveNotification doesn't need calling unless I
>
> want to explicitly stop observing something that is still going to be
>
> around. (in the same way you don't need to unregister Carbon Events on
>
> windows when they are disposed.)
Mike Engber said:
>
You do not have to remove observers, but in a sense you will be leaking
>
memory. There is a data structure in the API which holds the
>
AXUIElementRef, the notification, and the refcon. If you do not either
>
CFRelease the observer or remove the particular notification, then these
>
will hang around for ever.
OK, so my app now registers for kAXUIElementDestroyedNotification for all of
the windows it is interested in. To avoid the memory leak that Mike
mentions, I also call AXObserverRemoveNotification on the windows being
destroyed during the notification.
This works happily most of the time, except when a lot of windows are being
destroyed at the same time. For example, if you have a lot of windows open
in a Cocoa app (more than about 8 seems a good threshold) and hide that app,
then all of those windows are being destroyed at once.
Once the first one is hidden, my kAXUIElementDestroyedNotification gets
called and that then tries to remove the notification. The call to
AXObserverRemoveNotification then takes about 3 seconds (and seems to
timeout). During this time, none of the other windows in the hiding app are
hiding themselves. Once AXObserverRemoveNotification finishes, the next
window will hide and the slowness can repeat itself until all of the windows
have hidden.
i.e. with 10 windows to hide, it can take about 30 seconds before all the
windows get hidden.
Just to complicate things, sometimes several windows will hide themselves
quickly and then the the whole process will stall whilst all those windows
then get handled.
My guess as to what is happening is that it is something like this:
Anytime an AX API is called on an element, some interprocess communication
has to happen between the two apps involved. Since this can't just pre-empt
what the window owning app is doing such calls have to be handled inside its
CFRunLoop. Unfortunately during app hiding, this mechanism cannot fire and
the two apps get into a semi-deadlocked state until
AXObserverRemoveNotification times out.
Here is my Observer Proc:
void
CApplicationWindowWatcher::CApplicationWindowInfo::ObserverCallback(
AXObserverRef observer,
AXUIElementRef element,
CFStringRef notification,
void* refCon)
{
if (::CFEqual(notification, kAXUIElementDestroyedNotification))
{
AXError err = ::AXObserverRemoveNotification(observer, element,
notification);
}
}
So is there a solution to this that prevents this hanging?
How much of a memory leak are we talking about by not removing the observer,
and where does the leak occur (in my app, the other app, or the system in
general?)
Hoping for enlightenment
Matt Gough
P.S John & Mike, If you want me to send a build of my app then let me know.
_______________________________________________
accessibility-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/accessibility-dev
Do not post admin requests to the list. They will be ignored.