Browse Source

Merge pull request #9451 from AvaloniaUI/fixes/osx-native-menu-memory-leak

[OSX] Fixed NativeMenu memory leak
Max Katz 2 years ago
parent
commit
5e8b7ac858

+ 10 - 3
native/Avalonia.Native/src/OSX/menu.h

@@ -59,11 +59,20 @@ public:
     void RaiseOnClicked();
 };
 
+class AvnAppMenu;
+
+@interface AvnMenuDelegate : NSObject<NSMenuDelegate>
+- (id) initWithParent: (AvnAppMenu*) parent;
+- (void) parentDestroyed;
+@end
+
+
 class AvnAppMenu : public ComSingleObject<IAvnMenu, &IID_IAvnMenu>
 {
 private:
     AvnMenu* _native;
     ComPtr<IAvnMenuEvents> _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<NSMenuDelegate>
-- (id) initWithParent: (AvnAppMenu*) parent;
-@end
 
 #endif
 

+ 20 - 6
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<AvnAppMenu> _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

+ 2 - 0
src/Avalonia.MicroCom/CallbackBase.cs

@@ -32,6 +32,8 @@ namespace Avalonia.MicroCom
             if (_referencedFromManaged == false && _referencedFromNative == false)
             {
                 _destroyed = true;
+                Shadow?.Dispose();
+                Shadow = null;
                 Destroyed();
             }
         }

+ 1 - 12
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<NativeMenuItemBase, __MicroComIAvnMenuItemProxy> _menuItemLookup = new Dictionary<NativeMenuItemBase, __MicroComIAvnMenuItemProxy>();
@@ -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);