From 2469ba16ef4fec0882c2871124e1333034aecaaf Mon Sep 17 00:00:00 2001 From: Mike Kestner Date: Fri, 16 Feb 2007 16:18:59 +0000 Subject: [PATCH] 2007-02-16 Mike Kestner * glib/Object.cs : switch to ToggleRefs for all items created with CreateNativeObject. This gets all managed subclasses, with a little overhang into simple wrappers. * glib/ToggleRef.cs : new class to manage the weak to strong ref transitions as a native object flips between shared and unshared ownership. * gtk/Object.custom : revamp of the Destroyed signal handling. * gtk/Gtk.metadata : hide destroy signal so we can deal with it manually. [Fixes the reopen note of #72018.] svn path=/trunk/gtk-sharp/; revision=73023 --- ChangeLog | 12 +++++ glib/Makefile.am | 1 + glib/Object.cs | 24 ++++++---- glib/ToggleRef.cs | 110 ++++++++++++++++++++++++++++++++++++++++++++++ gtk/Gtk.metadata | 2 +- gtk/Object.custom | 78 ++++++++++++++++++++++++++------ 6 files changed, 204 insertions(+), 23 deletions(-) create mode 100644 glib/ToggleRef.cs diff --git a/ChangeLog b/ChangeLog index e3914cafc..f9da8154d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2007-02-16 Mike Kestner + + * glib/Object.cs : switch to ToggleRefs for all items created with + CreateNativeObject. This gets all managed subclasses, with a little + overhang into simple wrappers. + * glib/ToggleRef.cs : new class to manage the weak to strong ref + transitions as a native object flips between shared and unshared + ownership. + * gtk/Object.custom : revamp of the Destroyed signal handling. + * gtk/Gtk.metadata : hide destroy signal so we can deal with it + manually. [Fixes the reopen note of #72018.] + 2007-02-03 Mike Kestner * gtk/StatusIcon.custom : obsolete overload for backcompat on diff --git a/glib/Makefile.am b/glib/Makefile.am index d258b82bf..ef41307c2 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -55,6 +55,7 @@ sources = \ Source.cs \ Thread.cs \ Timeout.cs \ + ToggleRef.cs \ TypeConverter.cs \ TypeFundamentals.cs \ UnwrappedObject.cs \ diff --git a/glib/Object.cs b/glib/Object.cs index f9c8f8572..32f34d40e 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -63,7 +63,11 @@ namespace GLib { continue; try { - g_object_unref (o._obj); + ToggleRef toggle_ref = Objects [o._obj] as ToggleRef; + if (toggle_ref == null) + g_object_unref (o._obj); + else + toggle_ref.Free (); } catch (Exception e) { Console.WriteLine ("Exception while disposing a " + o + " in Gtk#"); throw e; @@ -101,13 +105,17 @@ namespace GLib { return null; Object obj = null; - WeakReference weak_ref = Objects[o] as WeakReference; + object reference = Objects[o]; - if (weak_ref != null && weak_ref.IsAlive) - obj = weak_ref.Target as Object; - - if (obj == null) - obj = Objects[o] as Object; + if (reference is WeakReference) { + WeakReference weak_ref = reference as WeakReference; + if (weak_ref.IsAlive) + obj = weak_ref.Target as Object; + } else if (reference is ToggleRef) { + ToggleRef toggle_ref = reference as ToggleRef; + if (toggle_ref.IsAlive) + obj = toggle_ref.Target; + } if (obj != null && obj._obj == o) { lock (PendingDestroys) @@ -247,7 +255,7 @@ namespace GLib { for (int i = 0; i < names.Length; i++) native_names [i] = GLib.Marshaller.StringToPtrGStrdup (names [i]); Raw = gtksharp_object_newv (LookupGType ().Val, names.Length, native_names, vals); - Objects [_obj] = this; + Objects [_obj] = new ToggleRef (this); foreach (IntPtr p in native_names) GLib.Marshaller.Free (p); } diff --git a/glib/ToggleRef.cs b/glib/ToggleRef.cs new file mode 100644 index 000000000..5dfae840e --- /dev/null +++ b/glib/ToggleRef.cs @@ -0,0 +1,110 @@ +// GLib.ToggleRef.cs - GLib ToggleRef class implementation +// +// Author: Mike Kestner +// +// Copyright 2007 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + + +namespace GLib { + + using System; + using System.Runtime.InteropServices; + + internal class ToggleRef { + + IntPtr handle; + object reference; + GCHandle gch; + + public ToggleRef (GLib.Object target) + { + handle = target.Handle; + gch = GCHandle.Alloc (this); + reference = target; + g_object_add_toggle_ref (target.Handle, ToggleNotifyCallback, (IntPtr) gch); + g_object_unref (target.Handle); + } + + public bool IsAlive { + get { + if (reference is WeakReference) { + WeakReference weak = reference as WeakReference; + return weak.IsAlive; + } + return true; + } + } + + public GLib.Object Target { + get { + if (reference is GLib.Object) + return reference as GLib.Object; + + WeakReference weak = reference as WeakReference; + return weak.Target as GLib.Object; + } + } + + public void Free () + { + g_object_remove_toggle_ref (handle, ToggleNotifyCallback, (IntPtr) gch); + gch.Free (); + } + + void Toggle (bool is_last_ref) + { + if (is_last_ref && reference is GLib.Object) + reference = new WeakReference (reference); + else if (!is_last_ref && reference is WeakReference) { + WeakReference weak = reference as WeakReference; + if (weak.IsAlive) + reference = weak.Target; + else + throw new Exception ("Toggling dead object wrapper"); + } + } + + [CDeclCallback] + delegate void ToggleNotifyHandler (IntPtr data, IntPtr handle, bool is_last_ref); + + static void RefToggled (IntPtr data, IntPtr handle, bool is_last_ref) + { + GCHandle gch = (GCHandle) data; + ToggleRef tref = gch.Target as ToggleRef; + tref.Toggle (is_last_ref); + } + + static ToggleNotifyHandler toggle_notify_callback; + static ToggleNotifyHandler ToggleNotifyCallback { + get { + if (toggle_notify_callback == null) + toggle_notify_callback = new ToggleNotifyHandler (RefToggled); + return toggle_notify_callback; + } + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_add_toggle_ref (IntPtr raw, ToggleNotifyHandler notify_cb, IntPtr data); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_remove_toggle_ref (IntPtr raw, ToggleNotifyHandler notify_cb, IntPtr data); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_unref (IntPtr raw); + + } +} diff --git a/gtk/Gtk.metadata b/gtk/Gtk.metadata index 66ebb89cf..2661dd36c 100644 --- a/gtk/Gtk.metadata +++ b/gtk/Gtk.metadata @@ -424,7 +424,7 @@ GtkDestroyNotify GtkDestroyNotify GtkDestroyNotify - Destroyed + 1 1 1 GetAcceptsPdf diff --git a/gtk/Object.custom b/gtk/Object.custom index d339726f8..58d96c767 100755 --- a/gtk/Object.custom +++ b/gtk/Object.custom @@ -1,8 +1,9 @@ // Gtk.Object.custom - Gtk Object class customizations // -// Author: Mike Kestner +// Author: Mike Kestner // // Copyright (c) 2002-2003 Mike Kestner +// Copyright (c) 2007 Novell, Inc. // // This code is inserted after the automatically generated code. // @@ -20,25 +21,66 @@ // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. + static Hashtable destroy_handlers; + static Hashtable DestroyHandlers { + get { + if (destroy_handlers == null) + destroy_handlers = new Hashtable (); + return destroy_handlers; + } + } - [DllImport("gtksharpglue-2")] - private static extern bool gtksharp_object_is_floating (IntPtr raw); + private static void OverrideDestroyed (GLib.GType gtype) + { + // Do Nothing. We don't want to hook into the native vtable. + // We will manually invoke the VM on signal invocation. The signal + // always raises before the default handler because this signal + // is RUN_CLEANUP. + } - [DllImport("gtksharpglue-2")] - private static extern bool gtksharp_object_set_floating (IntPtr raw, bool val); + [GLib.DefaultSignalHandler(Type=typeof(Gtk.Object), ConnectionMethod="OverrideDestroyed")] + protected virtual void OnDestroyed () + { + if (DestroyHandlers [Handle] == null) + return; - [DllImport("libgobject-2.0-0.dll")] - private static extern void g_object_ref (IntPtr raw); + EventHandler handler = (EventHandler) DestroyHandlers [Handle]; + handler (this, EventArgs.Empty); + DestroyHandlers [Handle] = null; + Dispose (); + } + + [GLib.Signal("destroy")] + public event EventHandler Destroyed { + add { + EventHandler handler = (EventHandler) DestroyHandlers [Handle]; + DestroyHandlers [Handle] = Delegate.Combine (handler, value); + } + remove { + EventHandler handler = (EventHandler) DestroyHandlers [Handle]; + DestroyHandlers [Handle] = Delegate.Remove (handler, value); + } + } + + event EventHandler InternalDestroyed { + add { + GLib.Signal sig = GLib.Signal.Lookup (this, "destroy"); + sig.AddDelegate (value); + } + remove { + GLib.Signal sig = GLib.Signal.Lookup (this, "destroy"); + sig.RemoveDelegate (value); + } + } static void NativeDestroy (object o, EventArgs args) { Gtk.Object obj = o as Gtk.Object; if (obj == null) return; - obj.Destroyed -= NativeDestroyHandler; - obj.Dispose (); + obj.OnDestroyed (); } - + static EventHandler native_destroy_handler; static EventHandler NativeDestroyHandler { get { @@ -51,15 +93,17 @@ protected override void CreateNativeObject (string[] names, GLib.Value[] vals) { base.CreateNativeObject (names, vals); - Destroyed += NativeDestroyHandler; } public override void Dispose () { + InternalDestroyed -= NativeDestroyHandler; base.Dispose (); - Destroyed -= NativeDestroyHandler; } + [DllImport("libgobject-2.0-0.dll")] + private static extern void g_object_ref_sink (IntPtr raw); + protected override IntPtr Raw { get { return base.Raw; @@ -69,8 +113,8 @@ if (value == IntPtr.Zero) return; - g_object_ref (value); - Sink (); + g_object_ref_sink (value); + InternalDestroyed += NativeDestroyHandler; } } @@ -82,6 +126,12 @@ gtk_object_destroy (Handle); } + [DllImport("gtksharpglue-2")] + private static extern bool gtksharp_object_is_floating (IntPtr raw); + + [DllImport("gtksharpglue-2")] + private static extern bool gtksharp_object_set_floating (IntPtr raw, bool val); + public bool IsFloating { get { return gtksharp_object_is_floating (Handle);