Skip to content

Commit

Permalink
Mac: Fix Window.Location when only SizeChanged is handled
Browse files Browse the repository at this point in the history
Also set EtoWindow/EtoPanel.Delegate to null when disposed for monomac, for the case the form is never shown, which fixes some unit tests.
  • Loading branch information
cwensley committed May 28, 2024
1 parent b52fb5b commit ba582b5
Showing 1 changed file with 34 additions and 7 deletions.
41 changes: 34 additions & 7 deletions src/Eto.Mac/Forms/MacWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ public override void RecalculateKeyViewLoop()
NSView last = null;
Handler?.RecalculateKeyViewLoop(ref last);
}

#if MONOMAC
protected override void Dispose(bool disposing)
{
// See HandleWillClose for details of this
// This is needed in addition when a window is created but not ever shown.
Delegate = null;
base.Dispose(disposing);
}
#endif
}

public class EtoPanel : NSPanel, IMacControl
Expand Down Expand Up @@ -147,6 +157,16 @@ public override void RecalculateKeyViewLoop()
NSView last = null;
Handler?.RecalculateKeyViewLoop(ref last);
}

#if MONOMAC
protected override void Dispose(bool disposing)
{
// See HandleWillClose for details of this
// This is needed in addition when a window is created but not ever shown.
Delegate = null;
base.Dispose(disposing);
}
#endif
}

class EtoContentView : MacPanelView
Expand Down Expand Up @@ -313,7 +333,17 @@ static void HandleWillClose(object sender, EventArgs e)
return;
handler.IsClosing = true;
if (ApplicationHandler.Instance.ShouldCloseForm(handler.Widget, true))
{
handler.Callback.OnClosed(handler.Widget, EventArgs.Empty);
#if MONOMAC
// AppKit still calls some delegate methods on the window after closing a form (e.g. WillReturnFieldEditor),
// causing exceptions trying to recreate the delegate if it has been garbage collected.
// This is because MonoMac doesn't use ref counting to determine when objects can be GC'd like MacOS.
// We avoid this problem by clearing out the delegate after the window is disposed.
// In Eto, we don't expect any events to be called after that point anyway.
handler.Control.Delegate = null;
#endif
}
handler.IsClosing = false;
}

Expand Down Expand Up @@ -411,6 +441,7 @@ public override void AttachEvent(string id)
}
}
});
HandleEvent(Window.LocationChangedEvent);
}
break;
case Window.LocationChangedEvent:
Expand Down Expand Up @@ -483,8 +514,8 @@ static void HandleWillMove(object sender, EventArgs e)
var newLocation = Point.Round(Mouse.Position - moveOffset);
if (handler.oldLocation != newLocation)
{
handler.Callback.OnLocationChanged(handler.Widget, EventArgs.Empty);
handler.oldLocation = newLocation;
handler.Callback.OnLocationChanged(handler.Widget, EventArgs.Empty);
}
// check for mouse up event
Expand Down Expand Up @@ -522,13 +553,9 @@ protected virtual void ConfigureWindow()
Control.ShouldZoom = HandleShouldZoom;
Control.WillMiniaturize += HandleWillMiniaturize;
Control.WillResize = HandleWillResize;

#if MONOMAC
// AppKit still calls some delegate methods on the window after closing a form (e.g. WillReturnFieldEditor),
// causing exceptions trying to recreate the delegate if it has been garbage collected.
// This is because MonoMac doesn't use ref counting to determine when objects can be GC'd like MacOS.
// We avoid this problem by clearing out the delegate after the window is closed.
// In Eto, we don't expect any events to be called after that point anyway.
Widget.Closed += (sender, e) => Application.Instance.AsyncInvoke(() => Control.Delegate = null);
HandleEvent(Window.ClosedEvent);
#endif
}

Expand Down

0 comments on commit ba582b5

Please sign in to comment.