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:
parent
9897c07f21
commit
70018d857d
5 changed files with 81 additions and 190 deletions
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
113
glib/Object.cs
113
glib/Object.cs
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue