Merge pull request #214 from GSharpKit/develop_pr_210125
Disposing of Widgets and Signals
This commit is contained in:
commit
402c57ae5a
7 changed files with 131 additions and 18 deletions
|
@ -54,7 +54,7 @@ namespace GLib {
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
Remove ();
|
Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cont;
|
return cont;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace GLib {
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
Remove ();
|
Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cont;
|
return cont;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue