2007-11-16 Mike Kestner <mkestner@novell.com>

* glib/Object.cs: use toggle refs for all objects.
	de-obsolete Data hash.  Add internal Signals hash.
	* glib/Signal.cs: switch to weak gchandles.
	* glib/WeakObject.cs: kill.

svn path=/trunk/gtk-sharp/; revision=89776
This commit is contained in:
Mike Kestner 2007-11-16 18:35:38 +00:00
parent 9897c07f21
commit 70018d857d
5 changed files with 81 additions and 190 deletions

View File

@ -1,3 +1,10 @@
2007-11-16 Mike Kestner <mkestner@novell.com>
* glib/Object.cs: use toggle refs for all objects.
de-obsolete Data hash. Add internal Signals hash.
* glib/Signal.cs: switch to weak gchandles.
* glib/WeakObject.cs: kill.
2007-11-16 Eskil Bylund <eskil@letterboxes.org>
* gtk/ListStore.custom:

View File

@ -67,8 +67,7 @@ sources = \
TypeInitializerAttribute.cs \
UnwrappedObject.cs \
ValueArray.cs \
Value.cs \
WeakObject.cs
Value.cs
build_sources = $(addprefix $(srcdir)/, $(sources)) AssemblyInfo.cs
dist_sources = $(sources)

View File

@ -31,7 +31,7 @@ namespace GLib {
public class Object : IWrapper, IDisposable {
IntPtr _obj;
IntPtr handle;
bool disposed = false;
Hashtable data;
static Hashtable Objects = new Hashtable();
@ -40,13 +40,15 @@ namespace GLib {
~Object ()
{
lock (PendingDestroys){
PendingDestroys.Add (this);
lock (typeof (Object)){
if (!idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs));
idle_queued = true;
}
lock (PendingDestroys) {
lock (Objects) {
if (Objects[Handle] is ToggleRef)
PendingDestroys.Add (Objects [Handle]);
Objects.Remove (Handle);
}
if (!idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs));
idle_queued = true;
}
}
}
@ -56,22 +58,18 @@ namespace GLib {
static bool PerformQueuedUnrefs ()
{
Object [] objects;
object [] references;
lock (PendingDestroys){
objects = new Object [PendingDestroys.Count];
PendingDestroys.CopyTo (objects, 0);
references = new object [PendingDestroys.Count];
PendingDestroys.CopyTo (references, 0);
PendingDestroys.Clear ();
}
lock (typeof (Object))
idle_queued = false;
foreach (Object o in objects){
if (o._obj == IntPtr.Zero)
continue;
o.Dispose ();
}
foreach (ToggleRef r in references)
r.Free ();
return false;
}
@ -82,17 +80,15 @@ namespace GLib {
disposed = true;
try {
ToggleRef toggle_ref = Objects [_obj] as ToggleRef;
if (toggle_ref == null)
g_object_unref (_obj);
else
ToggleRef toggle_ref = Objects [Handle] as ToggleRef;
if (toggle_ref != null)
toggle_ref.Free ();
} catch (Exception e) {
Console.WriteLine ("Exception while disposing a " + this + " in Gtk#");
throw e;
}
Objects.Remove (_obj);
_obj = IntPtr.Zero;
Objects.Remove (Handle);
handle = IntPtr.Zero;
GC.SuppressFinalize (this);
}
@ -105,34 +101,28 @@ namespace GLib {
return null;
Object obj = null;
object reference = Objects[o];
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)
if (Objects.Contains (o)) {
ToggleRef toggle_ref = Objects [o] as ToggleRef;
if (toggle_ref != null && toggle_ref.IsAlive)
obj = toggle_ref.Target;
}
if (obj != null && obj._obj == o) {
lock (PendingDestroys)
PendingDestroys.Remove (obj);
if (obj != null && obj.Handle == o) {
if (owned_ref)
g_object_unref (obj._obj);
obj.disposed = false;
g_object_unref (obj.Handle);
return obj;
}
obj = GLib.ObjectManager.CreateObject(o);
if (obj == null)
return null;
if (!owned_ref)
g_object_ref (obj.Handle);
Objects [o] = new WeakReference (obj);
obj = GLib.ObjectManager.CreateObject(o);
if (obj == null) {
g_object_unref (o);
return null;
}
return obj;
}
@ -292,22 +282,27 @@ 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] = new ToggleRef (this);
foreach (IntPtr p in native_names)
GLib.Marshaller.Free (p);
}
protected virtual IntPtr Raw {
get {
return _obj;
return handle;
}
set {
if (_obj != IntPtr.Zero)
Objects.Remove (_obj);
_obj = value;
if (value == IntPtr.Zero)
if (handle == value)
return;
Objects [value] = new WeakReference (this);
if (handle != IntPtr.Zero) {
ToggleRef tref = Objects [handle] as ToggleRef;
if (tref != null)
tref.Free ();
Objects.Remove (handle);
}
handle = value;
if (value != IntPtr.Zero)
Objects [value] = new ToggleRef (this);
}
}
@ -334,7 +329,16 @@ namespace GLib {
public IntPtr Handle {
get {
return _obj;
return handle;
}
}
Hashtable signals;
internal Hashtable Signals {
get {
if (signals == null)
signals = new Hashtable ();
return signals;
}
}
@ -436,7 +440,6 @@ namespace GLib {
return Handle.GetHashCode ();
}
[Obsolete("Can cause instability due to garbage collection of GLib.Objects.")]
public Hashtable Data {
get {
if (data == null)
@ -446,9 +449,13 @@ namespace GLib {
}
}
Hashtable persistent_data;
protected Hashtable PersistentData {
get {
return WeakObject.Lookup (Handle).Data;
if (persistent_data == null)
persistent_data = new Hashtable ();
return persistent_data;
}
}

View File

@ -45,7 +45,7 @@ namespace GLib {
public class Signal {
GCHandle gc_handle;
IntPtr handle;
Object obj;
string name;
uint before_id = UInt32.MaxValue;
uint after_id = UInt32.MaxValue;
@ -53,14 +53,11 @@ namespace GLib {
private Signal (GLib.Object obj, string signal_name, Delegate marshaler)
{
handle = obj.Handle;
this.obj = obj;
name = signal_name;
this.marshaler = marshaler;
gc_handle = GCHandle.Alloc (this);
IntPtr native_key = GLib.Marshaller.StringToPtrGStrdup (name + "_signal_marshaler");
if (handle != IntPtr.Zero)
g_object_set_data_full (handle, native_key, (IntPtr) gc_handle, DestroyHelper.NotifyHandler);
GLib.Marshaller.Free (native_key);
gc_handle = GCHandle.Alloc (this, GCHandleType.Weak);
obj.Signals [name] = this;
}
public static Signal Lookup (GLib.Object obj, string name)
@ -70,18 +67,10 @@ namespace GLib {
public static Signal Lookup (GLib.Object obj, string name, Delegate marshaler)
{
IntPtr native_key = GLib.Marshaller.StringToPtrGStrdup (name + "_signal_marshaler");
IntPtr data;
if (obj.Handle == IntPtr.Zero)
data = IntPtr.Zero;
else
data = g_object_get_data (obj.Handle, native_key);
GLib.Marshaller.Free (native_key);
if (data == IntPtr.Zero)
return new Signal (obj, name, marshaler);
GCHandle gch = (GCHandle) data;
return gch.Target as Signal;
Signal result = obj.Signals [name] as Signal;
if (result == null)
result = new Signal (obj, name, marshaler);
return result as Signal;
}
Delegate before_handler;
@ -89,7 +78,7 @@ namespace GLib {
public Delegate Handler {
get {
InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (handle), typeof (InvocationHint));
InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (obj.Handle), typeof (InvocationHint));
if (hint.run_type == SignalFlags.RunFirst)
return before_handler;
else
@ -100,7 +89,7 @@ namespace GLib {
uint Connect (int flags)
{
IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name);
uint id = g_signal_connect_data (handle, native_name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, flags);
uint id = g_signal_connect_data (obj.Handle, native_name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, flags);
GLib.Marshaller.Free (native_name);
return id;
}
@ -139,21 +128,13 @@ namespace GLib {
}
if (after_id == UInt32.MaxValue && before_id == UInt32.MaxValue)
DisconnectObject ();
}
void DisconnectObject ()
{
IntPtr native_key = GLib.Marshaller.StringToPtrGStrdup (name + "_signal_marshaler");
if (handle != IntPtr.Zero)
g_object_set_data (handle, native_key, IntPtr.Zero);
GLib.Marshaller.Free (native_key);
obj.Signals.Remove (name);
}
void DisconnectHandler (uint handler_id)
{
if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (handle, handler_id))
g_signal_handler_disconnect (handle, handler_id);
if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (obj.Handle, handler_id))
g_signal_handler_disconnect (obj.Handle, handler_id);
}
[CDeclCallback]
@ -186,15 +167,6 @@ namespace GLib {
}
}
[DllImport("libgobject-2.0-0.dll")]
static extern IntPtr g_object_get_data (IntPtr instance, IntPtr key);
[DllImport("libgobject-2.0-0.dll")]
static extern void g_object_set_data (IntPtr instance, IntPtr key, IntPtr data);
[DllImport("libgobject-2.0-0.dll")]
static extern void g_object_set_data_full (IntPtr instance, IntPtr key, IntPtr data, DestroyNotify notify);
[DllImport("libgobject-2.0-0.dll")]
static extern uint g_signal_connect_data(IntPtr obj, IntPtr name, Delegate cb, IntPtr gc_handle, IntPtr dummy, int flags);

View File

@ -1,94 +0,0 @@
// WeakObject.cs - Object to hold managed references via native weakref.
//
// Authors: Mike Kestner <mkestner@novell.com>
//
// Copyright (c) 2005 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.Collections;
using System.Runtime.InteropServices;
internal class WeakObject {
GCHandle gc_handle;
static DestroyNotify notify = new DestroyNotify (OnNativeDestroy);
[CDeclCallback]
delegate void DestroyNotify (IntPtr data);
static void OnNativeDestroy (IntPtr data)
{
try {
GCHandle gch = (GCHandle) data;
WeakObject obj = gch.Target as WeakObject;
obj.Dispose ();
gch.Free ();
} catch (Exception e) {
ExceptionManager.RaiseUnhandledException (e, false);
}
}
void Dispose ()
{
signals = null;
data = null;
}
WeakObject (IntPtr obj)
{
gc_handle = GCHandle.Alloc (this);
g_object_set_data_full (obj, "gtk_sharp_weak_object", (IntPtr) gc_handle, notify);
}
Hashtable data;
public Hashtable Data {
get {
if (data == null)
data = new Hashtable ();
return data;
}
}
Hashtable signals;
public Hashtable Signals {
get {
if (signals == null)
signals = new Hashtable ();
return signals;
}
}
public static WeakObject Lookup (IntPtr obj)
{
IntPtr data = g_object_get_data (obj, "gtk_sharp_weak_object");
if (data == IntPtr.Zero)
return new WeakObject (obj);
GCHandle gch = (GCHandle) data;
return gch.Target as WeakObject;
}
[DllImport("libgobject-2.0-0.dll")]
static extern IntPtr g_object_get_data (IntPtr instance, string key);
[DllImport("libgobject-2.0-0.dll")]
static extern void g_object_set_data_full (IntPtr instance, string key, IntPtr data, DestroyNotify notify);
}
}