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

* 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
This commit is contained in:
Mike Kestner 2007-02-16 16:18:59 +00:00
parent 33dc5b11e5
commit 2469ba16ef
6 changed files with 204 additions and 23 deletions

View File

@ -1,3 +1,15 @@
2007-02-16 Mike Kestner <mkestner@novell.com>
* 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 <mkestner@novell.com>
* gtk/StatusIcon.custom : obsolete overload for backcompat on

View File

@ -55,6 +55,7 @@ sources = \
Source.cs \
Thread.cs \
Timeout.cs \
ToggleRef.cs \
TypeConverter.cs \
TypeFundamentals.cs \
UnwrappedObject.cs \

View File

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

110
glib/ToggleRef.cs Normal file
View File

@ -0,0 +1,110 @@
// GLib.ToggleRef.cs - GLib ToggleRef class implementation
//
// Author: Mike Kestner <mkestner@novell.com>
//
// Copyright <c> 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);
}
}

View File

@ -424,7 +424,7 @@
<attr path="/api/namespace/object[@cname='GtkObject']/method[@name='SetDataByIdFull']/*/*[@name='destroy']" name="type">GtkDestroyNotify</attr>
<attr path="/api/namespace/object[@cname='GtkObject']/method[@name='Weakref']/*/*[@name='notify']" name="type">GtkDestroyNotify</attr>
<attr path="/api/namespace/object[@cname='GtkObject']/method[@name='Weakunref']/*/*[@name='notify']" name="type">GtkDestroyNotify</attr>
<attr path="/api/namespace/object[@cname='GtkObject']/signal[@name='Destroy']" name="name">Destroyed</attr>
<attr path="/api/namespace/object[@cname='GtkObject']/signal[@name='Destroy']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkPlug']/constructor[@cname='gtk_plug_new']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkPlug']/constructor[@cname='gtk_plug_new_for_display']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkPrinter']/method[@name='AcceptsPdf']" name="name">GetAcceptsPdf</attr>

View File

@ -1,8 +1,9 @@
// Gtk.Object.custom - Gtk Object class customizations
//
// Author: Mike Kestner <mkestner@speakeasy.net>
// Author: Mike Kestner <mkestner@novell.com>
//
// 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);