Merge pull request #214 from GSharpKit/develop_pr_210125

Disposing of Widgets and Signals
This commit is contained in:
Harry 2021-02-25 12:35:28 +01:00 committed by GitHub
commit 402c57ae5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 131 additions and 18 deletions

View file

@ -54,7 +54,7 @@ namespace GLib {
{ {
lock (this) lock (this)
{ {
Remove (); Dispose();
} }
} }
return cont; return cont;

View file

@ -33,7 +33,7 @@ namespace GLib {
IntPtr handle; IntPtr handle;
ToggleRef tref; ToggleRef tref;
bool disposed = false; bool disposed;
static uint idx = 1; static uint idx = 1;
static Dictionary<IntPtr, ToggleRef> Objects = new Dictionary<IntPtr, ToggleRef>(); static Dictionary<IntPtr, ToggleRef> Objects = new Dictionary<IntPtr, ToggleRef>();
static Dictionary<IntPtr, Dictionary<IntPtr, GLib.Value>> PropertiesToSet = new Dictionary<IntPtr, Dictionary<IntPtr, GLib.Value>>(); static Dictionary<IntPtr, Dictionary<IntPtr, GLib.Value>> PropertiesToSet = new Dictionary<IntPtr, Dictionary<IntPtr, GLib.Value>>();
@ -41,7 +41,7 @@ namespace GLib {
~Object () ~Object ()
{ {
if (WarnOnFinalize) if (WarnOnFinalize)
Console.Error.WriteLine ("Unexpected finalization of " + GetType() + " instance. Consider calling Dispose."); Console.Error.WriteLine ("Unexpected finalization of " + GetType() + " instance. Consider calling Dispose. (" + handle.ToInt64 () + ")");
Dispose (false); Dispose (false);
} }
@ -51,9 +51,10 @@ namespace GLib {
if (disposed) if (disposed)
return; return;
GC.SuppressFinalize (this);
Dispose (true); Dispose (true);
disposed = true; disposed = true;
GC.SuppressFinalize (this);
} }
protected virtual void Dispose (bool disposing) protected virtual void Dispose (bool disposing)
@ -70,19 +71,25 @@ namespace GLib {
return; return;
if (disposing) if (disposing)
tref.Dispose ();
else
tref.QueueUnref ();
// Free all internal signals, else the garbage collector is not
// able to free the object.
if (signals != null)
{ {
foreach (var sig in signals.Keys) tref.Dispose ();
signals[sig].Free ();
if (signals != null)
{
foreach (var sig in signals.Keys)
signals[sig].Free ();
}
}
else
{
if (signals != null)
QueueSignalFree ();
tref.QueueUnref ();
} }
signals = null; signals = null;
disposed = true;
} }
public static bool WarnOnFinalize { get; set; } public static bool WarnOnFinalize { get; set; }
@ -807,6 +814,9 @@ namespace GLib {
GLib.Marshaller.Free (native_name); GLib.Marshaller.Free (native_name);
} }
public static List<Signal> PendingSignalFrees = new List<Signal> ();
static bool idle_queued;
Dictionary<string, Signal> signals; Dictionary<string, Signal> signals;
Dictionary<string, Signal> Signals { Dictionary<string, Signal> Signals {
get { get {
@ -853,6 +863,34 @@ namespace GLib {
sig.RemoveDelegate (handler); sig.RemoveDelegate (handler);
} }
public void QueueSignalFree ()
{
lock (PendingSignalFrees) {
PendingSignalFrees.AddRange (signals.Values);
if (!idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformQueuedSignalFrees));
idle_queued = true;
}
}
}
static bool PerformQueuedSignalFrees ()
{
Signal[] qsignals;
lock (PendingSignalFrees){
qsignals = new Signal[PendingSignalFrees.Count];
PendingSignalFrees.CopyTo (qsignals, 0);
PendingSignalFrees.Clear ();
idle_queued = false;
}
foreach (Signal s in qsignals)
s.Free ();
return false;
}
protected static void OverrideVirtualMethod (GType gtype, string name, Delegate cb) protected static void OverrideVirtualMethod (GType gtype, string name, Delegate cb)
{ {
Signal.OverrideDefaultHandler (gtype, name, cb); Signal.OverrideDefaultHandler (gtype, name, cb);

View file

@ -52,7 +52,7 @@ namespace GLib {
{ {
lock (this) lock (this)
{ {
Remove (); Dispose();
} }
} }
return cont; return cont;

View file

@ -71,8 +71,12 @@ namespace GLib {
g_object_unref (handle); g_object_unref (handle);
else else
g_object_remove_toggle_ref (handle, ToggleNotifyCallback, (IntPtr) gch); g_object_remove_toggle_ref (handle, ToggleNotifyCallback, (IntPtr) gch);
reference = null; reference = null;
gch.Free ();
QueueGCHandleFree ();
handle = IntPtr.Zero;
} }
internal void Harden () internal void Harden ()
@ -97,7 +101,8 @@ namespace GLib {
reference = new WeakReference (reference); reference = new WeakReference (reference);
else if (!is_last_ref && reference is WeakReference) { else if (!is_last_ref && reference is WeakReference) {
WeakReference weak = reference as WeakReference; WeakReference weak = reference as WeakReference;
reference = weak.Target; if (weak.IsAlive)
reference = weak.Target;
} }
} }
@ -124,6 +129,37 @@ namespace GLib {
} }
} }
static List<GCHandle> PendingGCHandleFrees = new List<GCHandle> ();
static bool gc_idle_queued;
public void QueueGCHandleFree ()
{
lock (PendingGCHandleFrees) {
PendingGCHandleFrees.Add (gch);
if (!gc_idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformGCHandleFrees));
gc_idle_queued = true;
}
}
}
static bool PerformGCHandleFrees ()
{
GCHandle[] handles;
lock (PendingGCHandleFrees){
handles = new GCHandle [PendingGCHandleFrees.Count];
PendingGCHandleFrees.CopyTo (handles, 0);
PendingGCHandleFrees.Clear ();
gc_idle_queued = false;
}
foreach (GCHandle r in handles)
r.Free ();
return false;
}
static List<ToggleRef> PendingDestroys = new List<ToggleRef> (); static List<ToggleRef> PendingDestroys = new List<ToggleRef> ();
static bool idle_queued; static bool idle_queued;

View file

@ -151,6 +151,16 @@ namespace Gtk {
GLib.Marshaller.Free (native_name); GLib.Marshaller.Free (native_name);
return raw_ret; return raw_ret;
} }
[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"));
public IntPtr GetRawOwnedObject(string name) {
IntPtr raw_ret = GetRawObject (name);
g_object_ref (raw_ret);
return raw_ret;
}
public Builder (System.IO.Stream s) : this (s, null) public Builder (System.IO.Stream s) : this (s, null)
{ {

View file

@ -26,7 +26,7 @@ namespace Gtk {
delegate IntPtr d_gtk_message_dialog_new_with_markup(IntPtr parent_window, DialogFlags flags, MessageType type, ButtonsType bt, IntPtr msg, IntPtr args); delegate IntPtr d_gtk_message_dialog_new_with_markup(IntPtr parent_window, DialogFlags flags, MessageType type, ButtonsType bt, IntPtr msg, IntPtr args);
static d_gtk_message_dialog_new_with_markup gtk_message_dialog_new_with_markup = FuncLoader.LoadFunction<d_gtk_message_dialog_new_with_markup>(FuncLoader.GetProcAddress(GLibrary.Load(Library.Gtk), "gtk_message_dialog_new_with_markup")); static d_gtk_message_dialog_new_with_markup gtk_message_dialog_new_with_markup = FuncLoader.LoadFunction<d_gtk_message_dialog_new_with_markup>(FuncLoader.GetProcAddress(GLibrary.Load(Library.Gtk), "gtk_message_dialog_new_with_markup"));
public MessageDialog (Gtk.Window parent_window, DialogFlags flags, MessageType type, ButtonsType bt, bool use_markup, string format, params object[] args) public MessageDialog (Gtk.Window parent_window, DialogFlags flags, MessageType type, ButtonsType bt, bool use_markup, string format, params object[] args) : base (IntPtr.Zero)
{ {
IntPtr p = (parent_window != null) ? parent_window.Handle : IntPtr.Zero; IntPtr p = (parent_window != null) ? parent_window.Handle : IntPtr.Zero;

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;
} }
} }