From c7d76e49e452624eed55f9527df01b8059182b53 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 16 Nov 2022 15:35:51 +0600 Subject: [PATCH] [OSX] Fixed NativeMenu memory leak --- native/Avalonia.Native/src/OSX/menu.h | 13 ++++++++++--- native/Avalonia.Native/src/OSX/menu.mm | 26 ++++++++++++++++++++------ src/Avalonia.MicroCom/CallbackBase.cs | 2 ++ src/Avalonia.Native/IAvnMenu.cs | 13 +------------ 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h index ce46ac11e0..405938318c 100644 --- a/native/Avalonia.Native/src/OSX/menu.h +++ b/native/Avalonia.Native/src/OSX/menu.h @@ -59,11 +59,20 @@ public: void RaiseOnClicked(); }; +class AvnAppMenu; + +@interface AvnMenuDelegate : NSObject +- (id) initWithParent: (AvnAppMenu*) parent; +- (void) parentDestroyed; +@end + + class AvnAppMenu : public ComSingleObject { private: AvnMenu* _native; ComPtr _baseEvents; + AvnMenuDelegate* _delegate; public: FORWARD_IUNKNOWN() @@ -83,12 +92,10 @@ public: virtual HRESULT SetTitle (char* utf8String) override; virtual HRESULT Clear () override; + virtual ~AvnAppMenu() override; }; -@interface AvnMenuDelegate : NSObject -- (id) initWithParent: (AvnAppMenu*) parent; -@end #endif diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index b05588a441..cd1871de21 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -292,8 +292,13 @@ void AvnAppMenuItem::RaiseOnClicked() AvnAppMenu::AvnAppMenu(IAvnMenuEvents* events) { _baseEvents = events; - id del = [[AvnMenuDelegate alloc] initWithParent: this]; - _native = [[AvnMenu alloc] initWithDelegate: del]; + _delegate = [[AvnMenuDelegate alloc] initWithParent: this]; + _native = [[AvnMenu alloc] initWithDelegate: _delegate]; +} + +AvnAppMenu::~AvnAppMenu() +{ + [_delegate parentDestroyed]; } @@ -394,7 +399,7 @@ HRESULT AvnAppMenu::Clear() @implementation AvnMenuDelegate { - ComPtr _parent; + AvnAppMenu* _parent; } - (id) initWithParent:(AvnAppMenu *)parent { @@ -402,6 +407,12 @@ HRESULT AvnAppMenu::Clear() _parent = parent; return self; } + +- (void) parentDestroyed +{ + _parent = nullptr; +} + - (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel { if(shouldCancel) @@ -416,17 +427,20 @@ HRESULT AvnAppMenu::Clear() - (void)menuNeedsUpdate:(NSMenu *)menu { - _parent->RaiseNeedsUpdate(); + if(_parent) + _parent->RaiseNeedsUpdate(); } - (void)menuWillOpen:(NSMenu *)menu { - _parent->RaiseOpening(); + if(_parent) + _parent->RaiseOpening(); } - (void)menuDidClose:(NSMenu *)menu { - _parent->RaiseClosed(); + if(_parent) + _parent->RaiseClosed(); } @end diff --git a/src/Avalonia.MicroCom/CallbackBase.cs b/src/Avalonia.MicroCom/CallbackBase.cs index 49d589a5fc..6c5ab225f6 100644 --- a/src/Avalonia.MicroCom/CallbackBase.cs +++ b/src/Avalonia.MicroCom/CallbackBase.cs @@ -32,6 +32,8 @@ namespace Avalonia.MicroCom if (_referencedFromManaged == false && _referencedFromNative == false) { _destroyed = true; + Shadow?.Dispose(); + Shadow = null; Destroyed(); } } diff --git a/src/Avalonia.Native/IAvnMenu.cs b/src/Avalonia.Native/IAvnMenu.cs index e413023f6d..7ce50c5126 100644 --- a/src/Avalonia.Native/IAvnMenu.cs +++ b/src/Avalonia.Native/IAvnMenu.cs @@ -44,7 +44,6 @@ namespace Avalonia.Native.Interop.Impl { partial class __MicroComIAvnMenuProxy { - private MenuEvents _events; private AvaloniaNativeMenuExporter _exporter; private List<__MicroComIAvnMenuItemProxy> _menuItems = new List<__MicroComIAvnMenuItemProxy>(); private Dictionary _menuItemLookup = new Dictionary(); @@ -71,25 +70,15 @@ namespace Avalonia.Native.Interop.Impl public static __MicroComIAvnMenuProxy Create(IAvaloniaNativeFactory factory) { - var events = new MenuEvents(); + using var events = new MenuEvents(); var menu = (__MicroComIAvnMenuProxy)factory.CreateMenu(events); events.Initialise(menu); - menu._events = events; - return menu; } - protected override void Dispose(bool disposing) - { - if (disposing) - { - _events.Dispose(); - } - } - private void RemoveAndDispose(__MicroComIAvnMenuItemProxy item) { _menuItemLookup.Remove(item.ManagedMenuItem);