vcl/inc/osx/a11ywrapper.h | 2 vcl/osx/a11yactionwrapper.mm | 10 ++- vcl/osx/a11ycomponentwrapper.mm | 5 + vcl/osx/a11yfactory.mm | 3 vcl/osx/a11yrolehelper.mm | 4 - vcl/osx/a11yselectionwrapper.mm | 12 +++ vcl/osx/a11ytextattributeswrapper.mm | 12 ++- vcl/osx/a11ytextwrapper.mm | 17 ++++- vcl/osx/a11ywrapper.mm | 110 ++++++++++++++++++++++------------- vcl/osx/a11ywrapperbutton.mm | 2 vcl/osx/a11ywrappercheckbox.mm | 4 + vcl/osx/a11ywrappercombobox.mm | 6 + vcl/osx/a11ywrappergroup.mm | 2 vcl/osx/a11ywrapperlist.mm | 2 vcl/osx/a11ywrapperradiobutton.mm | 4 + vcl/osx/a11ywrapperradiogroup.mm | 2 vcl/osx/a11ywrapperrow.mm | 2 vcl/osx/a11ywrapperscrollarea.mm | 2 vcl/osx/a11ywrapperscrollbar.mm | 2 vcl/osx/a11ywrappersplitter.mm | 2 vcl/osx/a11ywrapperstatictext.mm | 2 vcl/osx/a11ywrappertabgroup.mm | 2 vcl/osx/a11ywrappertextarea.mm | 2 vcl/osx/a11ywrappertoolbar.mm | 2 vcl/osx/salmenu.cxx | 1 25 files changed, 157 insertions(+), 57 deletions(-)
New commits: commit 0735a4306da86c6fa0390b85f1f391ec404b2699 Author: Patrick Luby <guibmac...@gmail.com> AuthorDate: Fri May 24 20:26:23 2024 -0400 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Sun May 26 09:52:41 2024 +0200 Related tdf#158914: fix memory leaks by calling (auto)release selectors Found the following memory leaks using Xcode's Instruments application: 1. Posting an NSAccessibilityUIElementDestroyedNotification notification causes [ AquaA11yWrapper isAccessibilityElement ] to be called on the object so mark the object as disposed before posting the destroyed notification and test for disposed in all of the standard NSAccessibility selectors to prevent any calls to likely disposed C++ accessibility objects. 2. In [ AquaA11yWrapper accessibilityHitTest: ], [ AquaA11yFactory wrapperForAccessibleContext: ] already retains the returned object so retaining it until the next call to this selector can lead to a memory leak when dragging selected cells in Calc to a new location. So autorelease the object so that transient objects stay alive but not past the next clearing of the autorelease pool. 3. [ AquaA11ySelectionWrapper selectedChildrenAttributeForElement: ] is expected to return an autoreleased object. 4. [ AquaA11yFactory wrapperForAccessible: ] is not a getter. It expects the caller to release the returned object. 5. CreateNSString() is not a getter. It expects the caller to release the returned string. Change-Id: I824740d7e3851b0c3e31e2c009860aa822c94222 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168034 Reviewed-by: Patrick Luby <guibomac...@gmail.com> Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Tested-by: Jenkins diff --git a/vcl/inc/osx/a11ywrapper.h b/vcl/inc/osx/a11ywrapper.h index 1eb4039c57e9..48fdd8e2a582 100644 --- a/vcl/inc/osx/a11ywrapper.h +++ b/vcl/inc/osx/a11ywrapper.h @@ -67,6 +67,7 @@ struct ReferenceWrapper ReferenceWrapper maReferenceWrapper; BOOL mActsAsRadioGroup; BOOL mIsTableCell; + BOOL mIsDisposed; } // NSAccessibility Protocol -(id)accessibilityAttributeValue:(NSString *)attribute; @@ -101,6 +102,7 @@ struct ReferenceWrapper -(NSWindow*)windowForParent; -(id)init; -(id)initWithAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) anAccessibleContext; +-(void)setDisposed; -(void) setDefaults: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext; +(void)setPopupMenuOpen:(BOOL)popupMenuOpen; -(css::accessibility::XAccessibleAction *)accessibleAction; diff --git a/vcl/osx/a11yactionwrapper.mm b/vcl/osx/a11yactionwrapper.mm index 9bea25c11934..77d670c958b6 100644 --- a/vcl/osx/a11yactionwrapper.mm +++ b/vcl/osx/a11yactionwrapper.mm @@ -55,7 +55,10 @@ NSMutableArray * actionNames = [ [ NSMutableArray alloc ] init ]; if ( [ wrapper accessibleAction ] ) { for ( int cnt = 0; cnt < [ wrapper accessibleAction ] -> getAccessibleActionCount(); cnt++ ) { - [ actionNames addObject: [ AquaA11yActionWrapper nativeActionNameFor: CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) ] ]; + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + [ actionNames addObject: [ AquaA11yActionWrapper nativeActionNameFor: [ CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) autorelease ] ] ]; } } return actionNames; @@ -64,7 +67,10 @@ +(void)doAction:(NSString *)action ofElement:(AquaA11yWrapper *)wrapper { if ( [ wrapper accessibleAction ] ) { for ( int cnt = 0; cnt < [ wrapper accessibleAction ] -> getAccessibleActionCount(); cnt++ ) { - if ( [ action isEqualToString: [ AquaA11yActionWrapper nativeActionNameFor: CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) ] ] ) { + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + if ( [ action isEqualToString: [ AquaA11yActionWrapper nativeActionNameFor: [ CreateNSString ( [ wrapper accessibleAction ] -> getAccessibleActionDescription ( cnt ) ) autorelease ] ] ] ) { [ wrapper accessibleAction ] -> doAccessibleAction ( cnt ); break; } diff --git a/vcl/osx/a11ycomponentwrapper.mm b/vcl/osx/a11ycomponentwrapper.mm index d9d6db175428..15363a66874f 100644 --- a/vcl/osx/a11ycomponentwrapper.mm +++ b/vcl/osx/a11ycomponentwrapper.mm @@ -48,7 +48,10 @@ using namespace ::com::sun::star::uno; +(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper { if ( [ wrapper accessibleExtendedComponent ] ) { - return CreateNSString ( [ wrapper accessibleExtendedComponent ] -> getToolTipText() ); + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + return [ CreateNSString ( [ wrapper accessibleExtendedComponent ] -> getToolTipText() ) autorelease ]; } else { return nil; } diff --git a/vcl/osx/a11yfactory.mm b/vcl/osx/a11yfactory.mm index 0783252c7e1f..27b5ad2d81f2 100644 --- a/vcl/osx/a11yfactory.mm +++ b/vcl/osx/a11yfactory.mm @@ -140,7 +140,6 @@ static bool enabled = false; } else { aWrapper = [ [ AquaA11yWrapper alloc ] initWithAccessibleContext: rxAccessibleContext ]; } - [ nativeRole release ]; [ aWrapper setActsAsRadioGroup: asRadioGroup ]; #if 0 /* #i102033# NSAccessibility does not seemt to know an equivalent for transient children. @@ -169,8 +168,8 @@ static bool enabled = false; // TODO: when RADIO_BUTTON search for associated RadioGroup-wrapper and delete that as well AquaA11yWrapper * theWrapper = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: NO ]; if ( theWrapper != nil ) { - NSAccessibilityPostNotification( theWrapper, NSAccessibilityUIElementDestroyedNotification ); [ [ AquaA11yFactory allWrapper ] removeObjectForKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ]; + [ theWrapper setDisposed ]; [ theWrapper release ]; } } diff --git a/vcl/osx/a11yrolehelper.mm b/vcl/osx/a11yrolehelper.mm index a1cf62f327cc..5b621a74e23a 100644 --- a/vcl/osx/a11yrolehelper.mm +++ b/vcl/osx/a11yrolehelper.mm @@ -144,17 +144,14 @@ using namespace ::com::sun::star::uno; id nativeRole = [ AquaA11yRoleHelper simpleMapNativeRoleFrom: accessibleContext ]; if ( accessibleContext -> getAccessibleRole() == AccessibleRole::LABEL ) { if ( accessibleContext -> getAccessibleChildCount() > 0 ) { - [ nativeRole release ]; nativeRole = NSAccessibilityOutlineRole; } else if ( accessibleContext -> getAccessibleParent().is() ) { Reference < XAccessibleContext > rxParentContext = accessibleContext -> getAccessibleParent() -> getAccessibleContext(); if ( rxParentContext.is() ) { NSString * roleParent = static_cast<NSString *>([ AquaA11yRoleHelper simpleMapNativeRoleFrom: rxParentContext.get() ]); if ( [ roleParent isEqualToString: NSAccessibilityOutlineRole ] ) { - [ nativeRole release ]; nativeRole = NSAccessibilityRowRole; } - [ roleParent release ]; } } } else if ( accessibleContext -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) { @@ -165,7 +162,6 @@ using namespace ::com::sun::star::uno; if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) { sal_Int64 nStateSet = rxAccessibleContext -> getAccessibleStateSet(); if ( !(nStateSet & AccessibleStateType::EDITABLE ) ) { - [ nativeRole release ]; nativeRole = NSAccessibilityPopUpButtonRole; } } diff --git a/vcl/osx/a11yselectionwrapper.mm b/vcl/osx/a11yselectionwrapper.mm index 9d3beee2d3aa..4c9d1c7bfcce 100644 --- a/vcl/osx/a11yselectionwrapper.mm +++ b/vcl/osx/a11yselectionwrapper.mm @@ -34,10 +34,13 @@ using namespace ::com::sun::star::uno; Reference< XAccessibleSelection > xAccessibleSelection = [ wrapper accessibleSelection ]; if( xAccessibleSelection.is() ) { - NSMutableArray * children = [ [ NSMutableArray alloc ] init ]; try { sal_Int64 n = xAccessibleSelection -> getSelectedAccessibleChildCount(); + // Related tdf#158914: implicitly call autorelease selector + // Callers expect this selector to return an autoreleased object. + NSMutableArray * children = [ NSMutableArray arrayWithCapacity: n ]; + // Fix hanging when selecting a column or row in Calc // When a Calc column is selected, the child count will be // at least a million. Constructing that many C++ Calc objects @@ -49,7 +52,12 @@ using namespace ::com::sun::star::uno; n = MAXIMUM_ACCESSIBLE_TABLE_CELLS; for ( sal_Int64 i=0 ; i < n ; ++i ) { - [ children addObject: [ AquaA11yFactory wrapperForAccessible: xAccessibleSelection -> getSelectedAccessibleChild( i ) ] ]; + // Related tdf#158914: explicitly call release selector + // [ AquaA11yFactory wrapperForAccessible: ] is not a getter. + // It expects the caller to release the returned object. + id child_wrapper = [ AquaA11yFactory wrapperForAccessible: xAccessibleSelection -> getSelectedAccessibleChild( i ) ]; + [ children addObject: child_wrapper ]; + [ child_wrapper release ]; } return children; diff --git a/vcl/osx/a11ytextattributeswrapper.mm b/vcl/osx/a11ytextattributeswrapper.mm index 4404dc646365..11b205a8039b 100644 --- a/vcl/osx/a11ytextattributeswrapper.mm +++ b/vcl/osx/a11ytextattributeswrapper.mm @@ -210,7 +210,10 @@ using namespace ::com::sun::star::uno; } else if ( property.Name == "CharFontName" ) { OUString fontname; property.Value >>= fontname; - [fontDescriptor setName:CreateNSString(fontname)]; + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + [ fontDescriptor setName: [ CreateNSString(fontname) autorelease ] ]; } else if ( property.Name == "CharWeight" ) { [fontDescriptor setBold:[AquaA11yTextAttributesWrapper convertBoldStyle:property]]; } else if ( property.Name == "CharPosture" ) { @@ -313,8 +316,11 @@ using namespace ::com::sun::star::uno; int endIndex = loc + len; int currentIndex = loc; try { - NSString * myString = CreateNSString ( [ wrapper accessibleText ] -> getText() ); // TODO: dirty fix for i87817 - string = [ [ NSMutableAttributedString alloc ] initWithString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ]; + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + NSString * myString = [ CreateNSString ( [ wrapper accessibleText ] -> getText() ) autorelease ]; // TODO: dirty fix for i87817 + string = [ [ NSMutableAttributedString alloc ] initWithString: [ CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) autorelease ] ]; [ string autorelease ]; if ( [ wrapper accessibleTextAttributes ] && [myString characterAtIndex:0] != 57361) { // TODO: dirty fix for i87817 [ string beginEditing ]; diff --git a/vcl/osx/a11ytextwrapper.mm b/vcl/osx/a11ytextwrapper.mm index cfd4ae7c1c22..5a932d38a231 100644 --- a/vcl/osx/a11ytextwrapper.mm +++ b/vcl/osx/a11ytextwrapper.mm @@ -39,7 +39,10 @@ using namespace ::com::sun::star::uno; @implementation AquaA11yTextWrapper : NSObject +(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper { - return CreateNSString ( [ wrapper accessibleText ] -> getText() ); + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + return [ CreateNSString ( [ wrapper accessibleText ] -> getText() ) autorelease ]; } +(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value @@ -54,7 +57,10 @@ using namespace ::com::sun::star::uno; } +(id)selectedTextAttributeForElement:(AquaA11yWrapper *)wrapper { - return CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() ); + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + return [ CreateNSString ( [ wrapper accessibleText ] -> getSelectedText() ) autorelease ]; } +(void)setSelectedTextAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value { @@ -175,9 +181,12 @@ using namespace ::com::sun::star::uno; +(id)stringForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range { int loc = [ range rangeValue ].location; int len = [ range rangeValue ].length; - NSMutableString * textRange = [ [ NSMutableString alloc ] init ]; + NSMutableString * textRange = [ NSMutableString string ]; try { - [ textRange appendString: CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) ]; + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + [ textRange appendString: [ CreateNSString ( [ wrapper accessibleText ] -> getTextRange ( loc, loc + len ) ) autorelease ] ]; } catch ( IndexOutOfBoundsException & ) { // empty } diff --git a/vcl/osx/a11ywrapper.mm b/vcl/osx/a11ywrapper.mm index 96808412e154..3793b3232d7d 100644 --- a/vcl/osx/a11ywrapper.mm +++ b/vcl/osx/a11ywrapper.mm @@ -84,10 +84,28 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { return self; } +-(void)setDisposed { + // Related: tdf#148453 Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + + mIsDisposed = YES; + + // Release all strong C++ references + maReferenceWrapper = ReferenceWrapper(); + + // Related tdf@158914 avoid resurrecting object's C++ references + // Posting an NSAccessibilityUIElementDestroyedNotification + // notification causes [ AquaA11yWrapper isAccessibilityElement ] + // to be called on the object so mark the object as disposed + // before posting the destroyed notification. + NSAccessibilityPostNotification( self, NSAccessibilityUIElementDestroyedNotification ); +} + -(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext { mActsAsRadioGroup = NO; maReferenceWrapper.rAccessibleContext = rxAccessibleContext; mIsTableCell = NO; + mIsDisposed = NO; // Querying all supported interfaces try { // XAccessibleComponent @@ -230,7 +248,6 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { if ( ! [ subRole isEqualToString: @"" ] ) { return subRole; } else { - [ subRole release ]; SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.10 accessibilityAttributeValue: return [ super accessibilityAttributeValue: NSAccessibilitySubroleAttribute ]; @@ -240,7 +257,10 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(id)titleAttribute { - return CreateNSString ( [ self accessibleContext ] -> getAccessibleName() ); + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + return [ CreateNSString ( [ self accessibleContext ] -> getAccessibleName() ) autorelease ]; } -(id)descriptionAttribute { @@ -249,7 +269,10 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } else if ( [ self accessibleExtendedComponent ] ) { return [ AquaA11yComponentWrapper descriptionAttributeForElement: self ]; } else { - return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() ); + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + return [ CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() ) autorelease ]; } } @@ -425,7 +448,10 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } -(id)helpAttribute { - return CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() ); + // Related tdf#158914: explicitly call autorelease selector + // CreateNSString() is not a getter. It expects the caller to + // release the returned string. + return [ CreateNSString ( [ self accessibleContext ] -> getAccessibleDescription() ) autorelease ]; } -(id)roleDescriptionAttribute { @@ -449,15 +475,11 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { // build string NSNumber * nIndex = [ NSNumber numberWithInt: index ]; NSNumber * nGroupsize = [ NSNumber numberWithInt: [ children count ] ]; - NSMutableString * value = [ [ NSMutableString alloc ] init ]; + NSMutableString * value = [ NSMutableString string ]; [ value appendString: @"radio button " ]; [ value appendString: [ nIndex stringValue ] ]; [ value appendString: @" of " ]; [ value appendString: [ nGroupsize stringValue ] ]; - // clean up and return string - [ nIndex release ]; - [ nGroupsize release ]; - [ children release ]; return value; } else { return [ AquaA11yRoleHelper getRoleDescriptionFrom: @@ -642,9 +664,6 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { titleElement = [ AquaA11yFactory wrapperForAccessibleContext: rxAccessible -> getAccessibleContext() ]; } } - if ( title ) { - [ title release ]; - } return titleElement; } else { return nil; @@ -687,6 +706,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(id)accessibilityAttributeValue:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return nil; SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << "]"); // #i90575# guard NSAccessibility protocol against unwanted access @@ -720,13 +741,15 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(BOOL)accessibilityIsIgnored { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return YES; SAL_INFO("vcl.a11y", "[" << self << " accessibilityIsIgnored]"); // #i90575# guard NSAccessibility protocol against unwanted access if ( isPopupMenuOpen ) { return NO; } - bool ignored = false; + BOOL ignored = false; try { sal_Int16 nRole = [ self accessibleContext ] -> getAccessibleRole(); switch ( nRole ) { @@ -754,6 +777,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return nil; SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeNames]"); // #i90575# guard NSAccessibility protocol against unwanted access @@ -817,21 +842,9 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { if ( [ self accessibleValue ] ) { [ AquaA11yValueWrapper addAttributeNamesTo: attributeNames ]; } - if ( nativeSubrole ) { - [ nativeSubrole release ]; - } - if ( title ) { - [ title release ]; - } // Related: tdf#153374 Don't release autoreleased attributeNames return attributeNames; } catch ( DisposedException & ) { // Object is no longer available - if ( nativeSubrole ) { - [ nativeSubrole release ]; - } - if ( title ) { - [ title release ]; - } // Related: tdf#153374 Don't release autoreleased attributeNames // Also, return an autoreleased empty array instead of a retained array. [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ]; @@ -842,6 +855,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NO; SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeIsSettable:" << attribute << "]"); bool isSettable = false; @@ -863,6 +878,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(NSArray *)accessibilityParameterizedAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; SAL_INFO("vcl.a11y", "[" << self << " accessibilityParameterizedAttributeNames]"); NSMutableArray * attributeNames = [ NSMutableArray array ]; @@ -876,6 +893,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return nil; SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << " forParameter:" << (static_cast<NSObject*>(parameter)) << "]"); SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: YES ]; @@ -902,6 +921,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return; SAL_INFO("vcl.a11y", "[" << self << " accessibilitySetValue:" << (static_cast<NSObject*>(value)) << " forAttribute:" << attribute << "]"); SEL methodSelector = [ self selectorForAttribute: attribute asGetter: NO withGetterParameter: NO ]; @@ -922,6 +943,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(id)accessibilityFocusedUIElement { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return nil; SAL_INFO("vcl.a11y", "[" << self << " accessibilityFocusedUIElement]"); // #i90575# guard NSAccessibility protocol against unwanted access @@ -976,9 +999,6 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { } else if ( enabled && [ self accessibleAction ] ) { wrapper = self ; } - [ parentRole release ]; - [ enabledAttr release ]; - [ role release ]; return wrapper; } @@ -989,6 +1009,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(BOOL)performAction:(NSString *)action { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NO; SAL_INFO("vcl.a11y", "[" << self << " accessibilityPerformAction:" << action << "]"); AquaA11yWrapper * actionResponder = [ self actionResponder ]; @@ -1002,6 +1024,8 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { -(NSArray *)accessibilityActionNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return nil; SAL_INFO("vcl.a11y", "[" << self << " accessibilityActionNames]"); NSArray * actionNames = nil; @@ -1009,7 +1033,7 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) { if ( actionResponder ) { actionNames = [ AquaA11yActionWrapper actionNamesForElement: actionResponder ]; } else { - actionNames = [ [ NSArray alloc ] init ]; + actionNames = [ NSArray array ]; } return actionNames; } @@ -1096,13 +1120,10 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, -(id)accessibilityHitTest:(NSPoint)point { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return nil; SAL_INFO("vcl.a11y", "[" << self << " accessibilityHitTest:" << point << "]"); - static id wrapper = nil; - if ( nil != wrapper ) { - [ wrapper release ]; - wrapper = nil; - } Reference < XAccessibleContext > hitChild; NSRect screenRect = [ [ NSScreen mainScreen ] frame ]; css::awt::Point hitPoint ( static_cast<sal_Int32>(point.x) , static_cast<sal_Int32>(screenRect.size.height - point.y) ); @@ -1139,12 +1160,16 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, hitChild = hitTestRunner ( hitPoint, maReferenceWrapper.rAccessibleContext ); } if ( hitChild.is() ) { - wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ]; + // Related tdf#158914: do not retain wrapper + // [ AquaA11yFactory wrapperForAccessibleContext: ] already retains + // the returned object so retaining it until the next call to this + // selector can lead to a memory leak when dragging selected cells + // in Calc to a new location. So autorelease the object so that + // transient objects stay alive but not past the next clearing of + // the autorelease pool. + return [ [ AquaA11yFactory wrapperForAccessibleContext: hitChild ] autorelease ]; } - if ( wrapper ) { - [ wrapper retain ]; // TODO: retain only when transient ? - } - return wrapper; + return nil; } #pragma mark - @@ -1546,6 +1571,8 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NSZeroRect; try { XAccessibleComponent *pAccessibleComponent = [ self accessibleComponent ]; @@ -1576,6 +1603,11 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, // don't explicitly report (non-)expanded state when not expandable if (aSelector == @selector(isAccessibilityExpanded)) { + // Acquire solar mutex during native accessibility calls + SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NO; + const sal_Int64 nStateSet = [ self accessibleContext ] -> getAccessibleStateSet(); if (!( nStateSet & AccessibleStateType::EXPANDABLE)) return false; diff --git a/vcl/osx/a11ywrapperbutton.mm b/vcl/osx/a11ywrapperbutton.mm index a2c0d0398fe9..d988e0b644b1 100644 --- a/vcl/osx/a11ywrapperbutton.mm +++ b/vcl/osx/a11ywrapperbutton.mm @@ -39,6 +39,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappercheckbox.mm b/vcl/osx/a11ywrappercheckbox.mm index 9e0f221985c9..7f78e68de836 100644 --- a/vcl/osx/a11ywrappercheckbox.mm +++ b/vcl/osx/a11ywrappercheckbox.mm @@ -39,6 +39,8 @@ -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NO; if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) { return NO; @@ -49,6 +51,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappercombobox.mm b/vcl/osx/a11ywrappercombobox.mm index bfcef7275e33..d9a0727d9deb 100644 --- a/vcl/osx/a11ywrappercombobox.mm +++ b/vcl/osx/a11ywrappercombobox.mm @@ -113,6 +113,8 @@ using namespace ::com::sun::star::uno; -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NO; if ( [ self textArea ] != nil && ( [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ] @@ -126,6 +128,8 @@ using namespace ::com::sun::star::uno; -(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return; if ( [ self textArea ] != nil && ( [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ] @@ -139,6 +143,8 @@ using namespace ::com::sun::star::uno; -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappergroup.mm b/vcl/osx/a11ywrappergroup.mm index 7ed70d47baba..f50d23677f59 100644 --- a/vcl/osx/a11ywrappergroup.mm +++ b/vcl/osx/a11ywrappergroup.mm @@ -33,6 +33,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperlist.mm b/vcl/osx/a11ywrapperlist.mm index 25b3fa37ac62..e1c3f4f09042 100644 --- a/vcl/osx/a11ywrapperlist.mm +++ b/vcl/osx/a11ywrapperlist.mm @@ -31,6 +31,8 @@ using namespace ::com::sun::star::accessibility; -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperradiobutton.mm b/vcl/osx/a11ywrapperradiobutton.mm index 5022cc18c22b..bd2d8bde6800 100644 --- a/vcl/osx/a11ywrapperradiobutton.mm +++ b/vcl/osx/a11ywrapperradiobutton.mm @@ -38,6 +38,8 @@ -(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return NO; if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] ) { return NO; @@ -48,6 +50,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperradiogroup.mm b/vcl/osx/a11ywrapperradiogroup.mm index 9768dbbb6988..0896439400bc 100644 --- a/vcl/osx/a11ywrapperradiogroup.mm +++ b/vcl/osx/a11ywrapperradiogroup.mm @@ -30,6 +30,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperrow.mm b/vcl/osx/a11ywrapperrow.mm index 0c140c82c62c..a00e210ad25b 100644 --- a/vcl/osx/a11ywrapperrow.mm +++ b/vcl/osx/a11ywrapperrow.mm @@ -36,6 +36,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperscrollarea.mm b/vcl/osx/a11ywrapperscrollarea.mm index 22037220d409..4fa30a9f0417 100644 --- a/vcl/osx/a11ywrapperscrollarea.mm +++ b/vcl/osx/a11ywrapperscrollarea.mm @@ -62,6 +62,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperscrollbar.mm b/vcl/osx/a11ywrapperscrollbar.mm index 4a4612d3bbd0..8117e391ba85 100644 --- a/vcl/osx/a11ywrapperscrollbar.mm +++ b/vcl/osx/a11ywrapperscrollbar.mm @@ -34,6 +34,8 @@ using namespace ::com::sun::star::accessibility; -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappersplitter.mm b/vcl/osx/a11ywrappersplitter.mm index 39ec496af2ac..993d8a0204d3 100644 --- a/vcl/osx/a11ywrappersplitter.mm +++ b/vcl/osx/a11ywrappersplitter.mm @@ -31,6 +31,8 @@ using namespace ::com::sun::star::accessibility; -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrapperstatictext.mm b/vcl/osx/a11ywrapperstatictext.mm index 114c4179e8d6..317de60ee832 100644 --- a/vcl/osx/a11ywrapperstatictext.mm +++ b/vcl/osx/a11ywrapperstatictext.mm @@ -37,6 +37,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappertabgroup.mm b/vcl/osx/a11ywrappertabgroup.mm index 3d32ccc041f0..de484a599414 100644 --- a/vcl/osx/a11ywrappertabgroup.mm +++ b/vcl/osx/a11ywrappertabgroup.mm @@ -29,6 +29,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappertextarea.mm b/vcl/osx/a11ywrappertextarea.mm index 354030fb9aef..a53550f08431 100644 --- a/vcl/osx/a11ywrappertextarea.mm +++ b/vcl/osx/a11ywrappertextarea.mm @@ -29,6 +29,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/a11ywrappertoolbar.mm b/vcl/osx/a11ywrappertoolbar.mm index 28b5d01328f0..e2d0ec5a2a89 100644 --- a/vcl/osx/a11ywrappertoolbar.mm +++ b/vcl/osx/a11ywrappertoolbar.mm @@ -29,6 +29,8 @@ -(NSArray *)accessibilityAttributeNames { // Related: tdf#148453 Acquire solar mutex during native accessibility calls SolarMutexGuard aGuard; + if ( mIsDisposed ) + return [ NSArray array ]; // Default Attributes NSMutableArray * attributeNames = [ NSMutableArray arrayWithArray: [ super accessibilityAttributeNames ] ]; diff --git a/vcl/osx/salmenu.cxx b/vcl/osx/salmenu.cxx index 6ea16a6588ae..800affc060ef 100644 --- a/vcl/osx/salmenu.cxx +++ b/vcl/osx/salmenu.cxx @@ -163,6 +163,7 @@ static void initAppMenu() pNewItem = [pAppMenu addItemWithTitle: pString action: nil keyEquivalent: @""]; + [pString release]; NSMenu *servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease]; [pNewItem setSubmenu: servicesMenu]; [NSApp setServicesMenu: servicesMenu];