Invoke Destroy in Dispose if the Widget IsToplevel and it is not already destroyed

If the Widget is a toplevel then we have not ref'ed the Object, so ref before destroying it, and let the freeing of the ToggleRef undo the ref.
This commit is contained in:
Mads Kruse Johnsen 2020-11-19 16:22:47 +01:00
parent c3364fd338
commit 470ce6cff7

View File

@ -370,6 +370,7 @@ namespace Gtk {
Gtk.Widget widget = o as Gtk.Widget; Gtk.Widget widget = o as Gtk.Widget;
if (widget == null) if (widget == null)
return; return;
widget.OnDestroyed (); widget.OnDestroyed ();
} }
@ -387,20 +388,41 @@ namespace Gtk {
base.CreateNativeObject (names, vals); base.CreateNativeObject (names, vals);
} }
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr d_g_object_ref(IntPtr raw);
static d_g_object_ref g_object_ref = FuncLoader.LoadFunction<d_g_object_ref>(FuncLoader.GetProcAddress(GLibrary.Load(Library.GObject), "g_object_ref"));
private bool destroyed;
protected override void Dispose (bool disposing) protected override void Dispose (bool disposing)
{ {
if (Handle == IntPtr.Zero) if (Handle == IntPtr.Zero)
return; return;
if (disposing && !destroyed && IsToplevel)
{
//If this is a TopLevel widget, then we do not hold a ref, only a toggle ref.
//Freeing our toggle ref expects a normal ref to exist, and therefore does not check if the object still exists.
//Take a ref here and let our toggle ref unref it.
g_object_ref (Handle);
gtk_widget_destroy (Handle);
destroyed = true;
}
InternalDestroyed -= NativeDestroyHandler; InternalDestroyed -= NativeDestroyHandler;
base.Dispose (disposing); base.Dispose (disposing);
} }
protected override IntPtr Raw { protected override IntPtr Raw {
get { get {
return base.Raw; return base.Raw;
} }
set { set {
if (Handle == value)
return;
base.Raw = value; base.Raw = value;
if (value != IntPtr.Zero) if (value != IntPtr.Zero)
InternalDestroyed += NativeDestroyHandler; InternalDestroyed += NativeDestroyHandler;
} }
@ -409,11 +431,18 @@ namespace Gtk {
delegate void d_gtk_widget_destroy(IntPtr raw); delegate void d_gtk_widget_destroy(IntPtr raw);
static d_gtk_widget_destroy gtk_widget_destroy = FuncLoader.LoadFunction<d_gtk_widget_destroy>(FuncLoader.GetProcAddress(GLibrary.Load(Library.Gtk), "gtk_widget_destroy")); static d_gtk_widget_destroy gtk_widget_destroy = FuncLoader.LoadFunction<d_gtk_widget_destroy>(FuncLoader.GetProcAddress(GLibrary.Load(Library.Gtk), "gtk_widget_destroy"));
public virtual void Destroy () public virtual void Destroy ()
{ {
if (Handle == IntPtr.Zero) if (Handle == IntPtr.Zero)
return; return;
if (destroyed)
return;
gtk_widget_destroy (Handle); gtk_widget_destroy (Handle);
destroyed = true;
InternalDestroyed -= NativeDestroyHandler; InternalDestroyed -= NativeDestroyHandler;
} }
} }