[Gtk-sharp-list] patch: managed TreeModel impl

Vladimir Vukicevic vladimir@pobox.com
Mon, 24 May 2004 15:47:18 -0700


This is a multi-part message in MIME format.
--------------040605080500060008070605
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit


Updated patch attached; fixed a lot of the out/ref business based on 
feedback from Mike.  We use TreeIter.Zero to indcate invalid (i.e. NULL) 
passed-in TreeIters.

	- Vlad

--------------040605080500060008070605
Content-Type: text/plain;
 name="managed_tree_model.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="managed_tree_model.patch"

Index: ChangeLog
===================================================================
RCS file: /cvs/public/gtk-sharp/ChangeLog,v
retrieving revision 1.818
diff -u -u -r1.818 ChangeLog
--- ChangeLog	24 May 2004 02:25:15 -0000	1.818
+++ ChangeLog	24 May 2004 21:58:39 -0000
@@ -1,3 +1,26 @@
+2004-05-24  Vladimir Vukicevic  <vladimir@pobox.com>
+
+	* gtk/TreeIter.custom: add TreeIter.Invalid static TreeIter
+
+	* gtk/Makefile.am, gtk/ManagedTreeModel.cs: added
+	ManagedTreeModel.cs
+
+	* sample/Makefile.am, sample/ManagedModelDemo.cs: added.
+	
+	* gtk/TreeModel.custom: commented out SetValue() methods.  These
+	are specific to ListStore and TreeStore; they should probably get
+	removed?
+	
+	* gtk/Gtk.metadata: Changed TreeModel.IterNext to ref from out
+	(it computes the next iter based on the passed-in one)
+
+	* glib/Object.cs (RegisterType): added BindingFlags.NonPublic
+	to GetProperty search for "GType" property.
+
+2004-05-23  Vladimir Vukicevic  <vladimir@pobox.com>
+
+	* gtk/TreeIter.custom: add accessor properties for UserData1/2/3
+
 2004-05-23  Mike Kestner  <mkestner@ximian.com>
 
 	* generator/SignalHandler.cs : put back the ObjectGen hack
Index: glib/Object.cs
===================================================================
RCS file: /cvs/public/gtk-sharp/glib/Object.cs,v
retrieving revision 1.64
diff -u -u -r1.64 Object.cs
--- glib/Object.cs	18 May 2004 05:06:10 -0000	1.64
+++ glib/Object.cs	24 May 2004 21:58:39 -0000
@@ -149,7 +149,7 @@
 			if (g_types.Contains (t))
 				return (GType) g_types [t];
 			
-			PropertyInfo pi = t.GetProperty ("GType", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public);
+			PropertyInfo pi = t.GetProperty ("GType", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
 			if (pi != null)
 				return (GType) pi.GetValue (null, null);
 			
Index: gtk/Gtk.metadata
===================================================================
RCS file: /cvs/public/gtk-sharp/gtk/Gtk.metadata,v
retrieving revision 1.56
diff -u -u -r1.56 Gtk.metadata
--- gtk/Gtk.metadata	10 May 2004 20:00:08 -0000	1.56
+++ gtk/Gtk.metadata	24 May 2004 21:58:39 -0000
@@ -53,7 +53,7 @@
   <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='GetIter']/*/*[@name='iter']" name="pass_as">out</attr>
   <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='GetValue']/*/*[@name='value']" name="pass_as">ref</attr>
   <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='IterChildren']/*/*[@name='iter']" name="pass_as">out</attr>
-  <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='IterNext']/*/*[@name='iter']" name="pass_as">out</attr>
+  <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='IterNext']/*/*[@name='iter']" name="pass_as">ref</attr>
   <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='IterNthChild']/*/*[@name='iter']" name="pass_as">out</attr>
   <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='IterParent']/*/*[@name='iter']" name="pass_as">out</attr>
   <attr path="/api/namespace/interface[@cname='GtkTreeModel']/method[@name='RowChanged']" name="name">EmitRowChanged</attr>
Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/public/gtk-sharp/gtk/Makefile.am,v
retrieving revision 1.13
diff -u -u -r1.13 Makefile.am
--- gtk/Makefile.am	14 May 2004 20:25:57 -0000	1.13
+++ gtk/Makefile.am	24 May 2004 21:58:39 -0000
@@ -23,7 +23,8 @@
 	ThreadNotify.cs			\
 	TreeNodeAttribute.cs		\
 	TreeNode.cs			\
-	TreeNodeValueAttribute.cs
+	TreeNodeValueAttribute.cs       \
+	ManagedTreeModel.cs
 
 build_sources = $(addprefix $(srcdir)/, $(sources)) AssemblyInfo.cs
 
Index: gtk/TreeIter.custom
===================================================================
RCS file: /cvs/public/gtk-sharp/gtk/TreeIter.custom,v
retrieving revision 1.3
diff -u -u -r1.3 TreeIter.custom
--- gtk/TreeIter.custom	12 Feb 2004 21:28:42 -0000	1.3
+++ gtk/TreeIter.custom	24 May 2004 21:58:39 -0000
@@ -19,3 +19,18 @@
                                 ti._user_data2 == _user_data2 &&
                                 ti._user_data3 == _user_data3;
                 }
+
+                public IntPtr UserData1 {
+                        get { return _user_data; }
+                        set { _user_data = value; }
+                }
+                
+                public IntPtr UserData2 {
+                        get { return _user_data2; }
+                        set { _user_data2 = value; }
+                }
+                
+                public IntPtr UserData3 {
+                        get { return _user_data3; }
+                        set { _user_data3 = value; }
+                }
Index: gtk/TreeModel.custom
===================================================================
RCS file: /cvs/public/gtk-sharp/gtk/TreeModel.custom,v
retrieving revision 1.2
diff -u -u -r1.2 TreeModel.custom
--- gtk/TreeModel.custom	1 Nov 2003 12:00:26 -0000	1.2
+++ gtk/TreeModel.custom	24 May 2004 21:58:39 -0000
@@ -18,6 +18,7 @@
 	/// <remarks>To be completed</remarks>
 	bool IterNthChild (out Gtk.TreeIter iter, int n);
 
+#if false
         void SetValue (Gtk.TreeIter iter, int column, bool value);
         void SetValue (Gtk.TreeIter iter, int column, double value);
 	void SetValue (Gtk.TreeIter iter, int column, int value);
@@ -25,4 +26,5 @@
 	void SetValue (Gtk.TreeIter iter, int column, float value);
 	void SetValue (Gtk.TreeIter iter, int column, uint value);
 	void SetValue (Gtk.TreeIter iter, int column, object value);
+#endif
 	object GetValue(Gtk.TreeIter iter, int column);
Index: sample/Makefile.am
===================================================================
RCS file: /cvs/public/gtk-sharp/sample/Makefile.am,v
retrieving revision 1.4
diff -u -u -r1.4 Makefile.am
--- sample/Makefile.am	14 May 2004 20:25:57 -0000	1.4
+++ sample/Makefile.am	24 May 2004 21:58:39 -0000
@@ -24,7 +24,7 @@
 VTE_ASSEMBLY=
 endif
 
-TARGETS = custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe treeviewdemo.exe managedtreeviewdemo.exe testdnd.exe $(GNOME_TARGETS) $(GLADE_TARGETS) $(VTE_TARGETS)
+TARGETS = custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe treeviewdemo.exe managedtreeviewdemo.exe managedmodeldemo.exe testdnd.exe $(GNOME_TARGETS) $(GLADE_TARGETS) $(VTE_TARGETS)
 
 assemblies=../glib/glib-sharp.dll ../pango/pango-sharp.dll ../atk/atk-sharp.dll ../gdk/gdk-sharp.dll ../gtk/gtk-sharp.dll $(GNOME_ASSEMBLY) $(GLADE_ASSEMBLY) $(VTE_ASSEMBLY)
 references=$(addprefix -r , $(assemblies))
@@ -71,6 +71,9 @@
 managedtreeviewdemo.exe: $(srcdir)/ManagedTreeViewDemo.cs $(assemblies)
 	$(CSC)  -out:managedtreeviewdemo.exe $(references) $(srcdir)/ManagedTreeViewDemo.cs
 
+managedmodeldemo.exe: $(srcdir)/ManagedModelDemo.cs $(assemblies)
+	$(CSC)  -out:managedmodeldemo.exe $(references) $(srcdir)/ManagedModelDemo.cs
+
 glade-viewer.exe: $(srcdir)/GladeViewer.cs $(assemblies)
 	$(CSC)  -out:glade-viewer.exe $(references) $(srcdir)/GladeViewer.cs
 
@@ -109,4 +112,6 @@
 	CairoSample.cs			\
 	TestDnd.cs			\
 	VteTest.cs			\
-	CustomCellRenderer.cs
+	CustomCellRenderer.cs		\
+	ManagedModelDemo.cs
+
--- /dev/null	2004-02-23 13:02:56.000000000 -0800
+++ gtk/ManagedTreeModel.cs	2004-05-24 15:40:31.118333272 -0700
@@ -0,0 +1,535 @@
+//
+// ManagedTreeModel.cs
+//
+// Managed framework for implementing TreeModels
+//
+// Author(s): Vladimir Vukicevic  <vladimir@pobox.com>
+
+namespace Gtk {
+  using System;
+  using System.Collections;
+  using System.Runtime.InteropServices;
+
+  public abstract class ManagedTreeModel : GLib.Object, TreeModel {
+
+    //
+    // TreeModel interface
+    //
+
+    //
+    // These are things that can be overriden by subclasses
+    //
+
+    public virtual Gtk.TreeModelFlags Flags {
+      get {
+	return (Gtk.TreeModelFlags) 0;
+      }
+    }
+
+    public abstract int NColumns { get; }
+
+    public abstract System.Type ColumnType (int index);
+
+    public virtual GLib.GType GetColumnType (int index) {
+      return GLibSharp.TypeConverter.LookupType (ColumnType (index));
+    }
+
+    public abstract bool GetIter (out Gtk.TreeIter iter, Gtk.TreePath path);
+
+    public abstract Gtk.TreePath GetPath (Gtk.TreeIter iter);
+
+    public abstract object GetValue (Gtk.TreeIter iter, int column);
+
+    public virtual void GetValue (Gtk.TreeIter iter, int column, ref GLib.Value value) {
+      object o = GetValue (iter, column);
+      if (o == null) {
+	value.Init (GLib.GType.Invalid);
+	return;
+      }
+      GLib.GType ctype = GLibSharp.TypeConverter.LookupType (o.GetType());
+      value.Init (ctype);
+      value.Val = o;
+    }
+
+    public abstract bool IterNext (ref Gtk.TreeIter iter);
+
+    public virtual bool IterHasChild (Gtk.TreeIter iter) {
+      return false;
+    }
+
+    public virtual bool IterChildren (out Gtk.TreeIter iter, Gtk.TreeIter parent) {
+      iter = TreeIter.Zero;
+      return false;
+    }
+
+    public virtual int IterNChildren (Gtk.TreeIter iter) {
+      return 0;
+    }
+
+    public virtual bool IterNthChild (out Gtk.TreeIter iter, Gtk.TreeIter parent, int n) {
+      iter = TreeIter.Zero;
+      return false;
+    }
+
+    public virtual bool IterParent (out Gtk.TreeIter iter, Gtk.TreeIter child) {
+      iter = TreeIter.Zero;
+      return false;
+    }
+
+    public virtual void RefNode (Gtk.TreeIter iter) {
+      // nothing
+    }
+
+    public virtual void UnrefNode (Gtk.TreeIter iter) {
+      // nothing
+    }
+
+    // events
+
+    public event Gtk.RowChangedHandler RowChanged {
+      add {
+	System.ComponentModel.EventHandlerList event_list = AfterHandlers;
+	Hashtable signals = AfterSignals;
+	if (value.Method.GetCustomAttributes (typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {
+	  event_list = BeforeHandlers;
+	  signals = BeforeSignals;
+	}
+
+	if (signals["row_changed"] == null)
+	  signals["row_changed"] = new GtkSharp.voidObjectTreePathTreeIterSignal
+	    (this, "row_changed", value, System.Type.GetType("Gtk.RowChangedHandler,gtk-sharp"), 0);
+	else
+	  ((GLib.SignalCallback) signals["row_changed"]).AddDelegate (value);
+
+	event_list.AddHandler("row_changed", value);
+      }
+
+      remove {
+	sigRemovalHelper (value, "row_changed");
+      }
+    }
+
+    public event Gtk.RowDeletedHandler RowDeleted {
+      add {
+	System.ComponentModel.EventHandlerList event_list = AfterHandlers;
+	Hashtable signals = AfterSignals;
+	if (value.Method.GetCustomAttributes (typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {
+	  event_list = BeforeHandlers;
+	  signals = BeforeSignals;
+	}
+
+	if (signals["row_deleted"] == null)
+	  signals["row_deleted"] = new GtkSharp.voidObjectTreePathSignal
+	    (this, "row_deleted", value, System.Type.GetType("Gtk.RowDeletedHandler,gtk-sharp"), 0);
+	else
+	  ((GLib.SignalCallback) signals["row_deleted"]).AddDelegate (value);
+
+	event_list.AddHandler("row_deleted", value);
+      }
+
+      remove {
+	sigRemovalHelper (value, "row_deleted");
+      }
+    }
+
+    public event Gtk.RowHasChildToggledHandler RowHasChildToggled {
+      add {
+	System.ComponentModel.EventHandlerList event_list = AfterHandlers;
+	Hashtable signals = AfterSignals;
+	if (value.Method.GetCustomAttributes (typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {
+	  event_list = BeforeHandlers;
+	  signals = BeforeSignals;
+	}
+
+	if (signals["row_has_child_toggled"] == null)
+	  signals["row_has_child_toggled"] = new GtkSharp.voidObjectTreePathTreeIterSignal
+	    (this, "row_has_child_toggled", value, System.Type.GetType("Gtk.RowHasChildToggledHandler,gtk-sharp"), 0);
+	else
+	  ((GLib.SignalCallback) signals["row_has_child_toggled"]).AddDelegate (value);
+
+	event_list.AddHandler("row_has_child_toggled", value);
+      }
+
+      remove {
+	sigRemovalHelper (value, "row_has_child_toggled");
+      }
+    }
+
+    public event Gtk.RowInsertedHandler RowInserted {
+      add {
+	System.ComponentModel.EventHandlerList event_list = AfterHandlers;
+	Hashtable signals = AfterSignals;
+	if (value.Method.GetCustomAttributes (typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {
+	  event_list = BeforeHandlers;
+	  signals = BeforeSignals;
+	}
+
+	if (signals["row_inserted"] == null)
+	  signals["row_inserted"] = new GtkSharp.voidObjectTreePathTreeIterSignal
+	    (this, "row_inserted", value, System.Type.GetType("Gtk.RowInsertedHandler,gtk-sharp"), 0);
+	else
+	  ((GLib.SignalCallback) signals["row_inserted"]).AddDelegate (value);
+
+	event_list.AddHandler("row_inserted", value);
+      }
+
+      remove {
+	sigRemovalHelper (value, "row_inserted");
+      }
+    }
+
+    public event Gtk.RowsReorderedHandler RowsReordered {
+      add {
+	System.ComponentModel.EventHandlerList event_list = AfterHandlers;
+	Hashtable signals = AfterSignals;
+	if (value.Method.GetCustomAttributes (typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {
+	  event_list = BeforeHandlers;
+	  signals = BeforeSignals;
+	}
+
+	if (signals["rows_reordered"] == null)
+	  signals["rows_reordered"] = new GtkSharp.voidObjectTreePathTreeIterintSignal
+	    (this, "rows_reordered", value, System.Type.GetType("Gtk.RowsReorderedHandler,gtk-sharp"), 0);
+	else
+	  ((GLib.SignalCallback) signals["rows_reordered"]).AddDelegate (value);
+
+	event_list.AddHandler("rows_reordered", value);
+      }
+
+      remove {
+	sigRemovalHelper (value, "rows_reordered");
+      }
+    }
+
+    private void sigRemovalHelper (Delegate d, string signame) {
+      System.ComponentModel.EventHandlerList event_list = AfterHandlers;
+      Hashtable signals = AfterSignals;
+      if (d.Method.GetCustomAttributes(typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {
+	event_list = BeforeHandlers;
+	signals = BeforeSignals;
+      }
+      GLib.SignalCallback cb = signals[signame] as GLib.SignalCallback;
+      event_list.RemoveHandler(signame, d);
+      if (cb == null)
+	return;
+
+      cb.RemoveDelegate(d);
+
+      if (event_list["rows_reordered"] == null) {
+	signals.Remove("rows_reordered");
+	cb.Dispose ();
+      }
+    }
+
+    /*
+     * These are methods that are defined on tree_model, but are not part of the interface itself.
+     * This code is duplicated in ListStore and TreeStore, which sucks; there really should be a way
+     * to have a common ancestor for these.
+     */
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_get_valist(IntPtr raw, ref Gtk.TreeIter iter, IntPtr var_args);
+    
+    public void GetValist(Gtk.TreeIter iter, IntPtr var_args) {
+      gtk_tree_model_get_valist(Handle, ref iter, var_args);
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern IntPtr gtk_tree_model_get_string_from_iter(IntPtr raw, ref Gtk.TreeIter iter);
+
+    public string GetStringFromIter(Gtk.TreeIter iter) {
+      IntPtr raw_ret = gtk_tree_model_get_string_from_iter(Handle, ref iter);
+      string ret = GLib.Marshaller.PtrToStringGFree(raw_ret);
+      return ret;
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern bool gtk_tree_model_get_iter_from_string(IntPtr raw, out Gtk.TreeIter iter, string path_string);
+
+    public bool GetIterFromString(out Gtk.TreeIter iter, string path_string) {
+      bool raw_ret = gtk_tree_model_get_iter_from_string(Handle, out iter, path_string);
+      bool ret = raw_ret;
+      return ret;
+    }
+
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern bool gtk_tree_model_get_iter_first(IntPtr raw, out Gtk.TreeIter iter);
+
+    public bool GetIterFirst(out Gtk.TreeIter iter) {
+      bool raw_ret = gtk_tree_model_get_iter_first(Handle, out iter);
+      bool ret = raw_ret;
+      return ret;
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_foreach(IntPtr raw, GtkSharp.TreeModelForeachFuncNative func, IntPtr user_data);
+
+    public void Foreach(Gtk.TreeModelForeachFunc func) {
+      GtkSharp.TreeModelForeachFuncWrapper func_wrapper = null;
+      func_wrapper = new GtkSharp.TreeModelForeachFuncWrapper (func, this);
+      gtk_tree_model_foreach(Handle, func_wrapper.NativeDelegate, IntPtr.Zero);
+    }
+
+
+    /* Signal emitters */
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_row_changed(IntPtr raw, IntPtr path, ref Gtk.TreeIter iter);
+
+    public void EmitRowChanged(Gtk.TreePath path, Gtk.TreeIter iter) {
+      gtk_tree_model_row_changed(Handle, path.Handle, ref iter);
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_row_deleted(IntPtr raw, IntPtr path);
+
+    public void EmitRowDeleted(Gtk.TreePath path) {
+      gtk_tree_model_row_deleted(Handle, path.Handle);
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_row_inserted(IntPtr raw, IntPtr path, ref Gtk.TreeIter iter);
+
+    public void EmitRowInserted(Gtk.TreePath path, Gtk.TreeIter iter) {
+      gtk_tree_model_row_inserted(Handle, path.Handle, ref iter);
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_row_has_child_toggled(IntPtr raw, IntPtr path, ref Gtk.TreeIter iter);
+
+    public void EmitRowHasChildToggled(Gtk.TreePath path, Gtk.TreeIter iter) {
+      gtk_tree_model_row_has_child_toggled(Handle, path.Handle, ref iter);
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern void gtk_tree_model_rows_reordered(IntPtr raw, IntPtr path, ref Gtk.TreeIter iter, out int new_order);
+
+    public int EmitRowsReordered(Gtk.TreePath path, Gtk.TreeIter iter) {
+      int new_order;
+      gtk_tree_model_rows_reordered(Handle, path.Handle, ref iter, out new_order);
+      return new_order;
+    }
+
+    /* Convenience bits */
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern bool gtk_tree_model_iter_children (IntPtr raw, ref Gtk.TreeIter iter, IntPtr parent);
+
+    public bool IterChildren (ref Gtk.TreeIter iter) {
+      bool raw_ret = gtk_tree_model_iter_children (Handle, ref iter, IntPtr.Zero);
+      bool ret = raw_ret;
+      return ret;
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern int gtk_tree_model_iter_n_children (IntPtr raw, IntPtr iter);
+
+    public int IterNChildren () {
+      int raw_ret = gtk_tree_model_iter_n_children (Handle, IntPtr.Zero);
+      int ret = raw_ret;
+      return ret;
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern bool gtk_tree_model_iter_nth_child (IntPtr raw, ref Gtk.TreeIter iter, IntPtr parent, int n);
+
+    public bool IterNthChild (ref Gtk.TreeIter iter, int n) {
+      bool raw_ret = gtk_tree_model_iter_nth_child (Handle, ref iter, IntPtr.Zero, n);
+      bool ret = raw_ret;
+      return ret;
+    }
+
+    /*
+     * ManagedTreeModel impl details.  Places where it's valid to pass
+     * in NULL for a TreeIter are passed in as IntPtrs and marshalled
+     * later.  These are in-only structs, so we don't have to marshal back.
+     */
+
+    internal delegate int TreeModelGetFlagsDelegate (IntPtr tree_model);
+    internal delegate int TreeModelGetNColumnsDelegate (IntPtr tree_model);
+    internal delegate IntPtr TreeModelGetColumnTypeDelegate (IntPtr tree_model, int index);
+    internal delegate bool TreeModelGetIterDelegate (IntPtr tree_model, out TreeIter iter, IntPtr path);
+    internal delegate IntPtr /* path */ TreeModelGetPathDelegate (IntPtr tree_model, /* ref TreeIter */ IntPtr iter);
+    internal delegate void TreeModelGetValueDelegate (IntPtr tree_model, ref TreeIter iter, int column, ref GLib.Value value);
+    internal delegate bool TreeModelIterNextDelegate (IntPtr tree_model, ref TreeIter iter);
+    internal delegate bool TreeModelIterChildrenDelegate (IntPtr tree_model, ref TreeIter iter, /* ref TreeIter */ IntPtr parent);
+    internal delegate bool TreeModelIterHasChildDelegate (IntPtr tree_model, /* ref TreeIter */ IntPtr iter);
+    internal delegate int TreeModelIterNChildrenDelegate (IntPtr tree_model, /* ref TreeIter */ IntPtr iter);
+    internal delegate bool TreeModelIterNthChildDelegate (IntPtr tree_model, out TreeIter iter, /* ref TreeIter */ IntPtr parent, int n);
+    internal delegate bool TreeModelIterParentDelegate (IntPtr tree_model, ref TreeIter iter, ref TreeIter child);
+    internal delegate void TreeModelRefNodeDelegate (IntPtr tree_model, ref TreeIter iter);
+    internal delegate void TreeModelUnrefNodeDelegate (IntPtr tree_model, ref TreeIter iter);
+
+    /* This is a copy of the TreeModel interface struct */
+    internal struct TreeModelInterface {
+      /* GLib.GTypeInterface */
+      internal IntPtr g_type;
+      internal IntPtr g_instance_type;
+
+      /* GtkTreeModel */
+      /* signals */
+      internal IntPtr row_changed;
+      internal IntPtr row_inserted;
+      internal IntPtr row_has_child_toggled;
+      internal IntPtr row_deleted;
+      internal IntPtr rows_reordered;
+
+      /* vtbl */
+      internal TreeModelGetFlagsDelegate get_flags;
+      internal TreeModelGetNColumnsDelegate get_n_columns;
+      internal TreeModelGetColumnTypeDelegate get_column_type;
+      internal TreeModelGetIterDelegate get_iter;
+      internal TreeModelGetPathDelegate get_path;
+      internal TreeModelGetValueDelegate get_value;
+      internal TreeModelIterNextDelegate iter_next;
+      internal TreeModelIterChildrenDelegate iter_children;
+      internal TreeModelIterHasChildDelegate iter_has_child;
+      internal TreeModelIterNChildrenDelegate iter_n_children;
+      internal TreeModelIterNthChildDelegate iter_nth_child;
+      internal TreeModelIterParentDelegate iter_parent;
+      internal TreeModelRefNodeDelegate ref_node;
+      internal TreeModelUnrefNodeDelegate unref_node;
+    }
+
+    // internal delegate void GTreeModelInterfaceInitFuncDelegate (ref TreeModelInterface iface, IntPtr data);
+    internal delegate void GTreeModelInterfaceInitFuncDelegate (IntPtr iface, IntPtr data);
+    internal delegate void GTreeModelInterfaceFinalizeFuncDelegate (ref TreeModelInterface iface, IntPtr data);
+
+    internal struct GInterfaceInfo {
+      internal GTreeModelInterfaceInitFuncDelegate init_func;
+      internal GTreeModelInterfaceFinalizeFuncDelegate finalize_func;
+      internal IntPtr iface_data;
+    }
+
+    [DllImport("libgtk-win32-2.0-0.dll")]
+    static extern IntPtr gtk_tree_model_get_type ();
+
+    [DllImport("libgobject-2.0-0.dll")]
+    static extern void g_type_add_interface_static (IntPtr instance_type,
+						    IntPtr interface_type,
+						    ref GInterfaceInfo info);
+
+    internal static GLib.GType ManagedTreeModelGType;
+    internal static GInterfaceInfo ManagedTreeModelInterfaceInfo;
+
+    internal static GLib.GType ManagedTreeModelGetType () {
+      if (ManagedTreeModelGType.Val == IntPtr.Zero) {
+	/* register this type */
+	ManagedTreeModelGType = GLib.Object.RegisterGType (typeof(ManagedTreeModel));
+
+	/* Add the TreeModel interface */
+	ManagedTreeModelInterfaceInfo.init_func = new GTreeModelInterfaceInitFuncDelegate (tree_model_iface_init);
+	g_type_add_interface_static (ManagedTreeModelGType.Val, gtk_tree_model_get_type(), ref ManagedTreeModelInterfaceInfo);
+      }
+
+      return ManagedTreeModelGType;
+    }
+
+    // internal static void tree_model_iface_init (ref TreeModelInterface iface, IntPtr data) {
+    internal static void tree_model_iface_init (IntPtr ifaceptr, IntPtr data) {
+      TreeModelInterface iface = (TreeModelInterface) Marshal.PtrToStructure (ifaceptr, typeof(TreeModelInterface));
+
+      iface.get_flags = new TreeModelGetFlagsDelegate (TreeModelGetFlagsImpl);
+      iface.get_n_columns = new TreeModelGetNColumnsDelegate (TreeModelGetNColumnsImpl);
+      iface.get_column_type = new TreeModelGetColumnTypeDelegate (TreeModelGetColumnTypeImpl);
+      iface.get_iter = new TreeModelGetIterDelegate (TreeModelGetIterImpl);
+      iface.get_path = new TreeModelGetPathDelegate (TreeModelGetPathImpl);
+      iface.get_value = new TreeModelGetValueDelegate (TreeModelGetValueImpl);
+      iface.iter_next = new TreeModelIterNextDelegate (TreeModelIterNextImpl);
+      iface.iter_children = new TreeModelIterChildrenDelegate (TreeModelIterChildrenImpl);
+      iface.iter_has_child = new TreeModelIterHasChildDelegate (TreeModelIterHasChildImpl);
+      iface.iter_n_children = new TreeModelIterNChildrenDelegate (TreeModelIterNChildrenImpl);
+      iface.iter_nth_child = new TreeModelIterNthChildDelegate (TreeModelIterNthChildImpl);
+      iface.iter_parent = new TreeModelIterParentDelegate (TreeModelIterParentImpl);
+      iface.ref_node = new TreeModelRefNodeDelegate (TreeModelRefNodeImpl);
+      iface.unref_node = new TreeModelUnrefNodeDelegate (TreeModelUnrefNodeImpl);
+
+      Marshal.StructureToPtr (iface, ifaceptr, false);
+    }
+
+    internal static int TreeModelGetFlagsImpl (IntPtr tree_model) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return (int) tm.Flags;
+    }
+
+    internal static int TreeModelGetNColumnsImpl (IntPtr tree_model) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.NColumns;
+    }
+
+    internal static IntPtr TreeModelGetColumnTypeImpl (IntPtr tree_model, int index) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.GetColumnType (index).Val;
+    }
+
+    internal static bool TreeModelGetIterImpl (IntPtr tree_model, out TreeIter iter, IntPtr path) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.GetIter (out iter, new TreePath(path));
+    }
+
+    internal static IntPtr /* path */ TreeModelGetPathImpl (IntPtr tree_model, /* ref TreeIter */ IntPtr iter) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      TreePath path = tm.GetPath (TreeIter.New (iter));
+      if (path == null)
+	return IntPtr.Zero;
+      return path.Handle;
+    }
+
+    internal static void TreeModelGetValueImpl (IntPtr tree_model, ref TreeIter iter, int column, ref GLib.Value value) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      tm.GetValue (iter, column, ref value);
+    }
+
+    internal static bool TreeModelIterNextImpl (IntPtr tree_model, ref TreeIter iter) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.IterNext (ref iter);
+    }
+
+    internal static bool TreeModelIterChildrenImpl (IntPtr tree_model, ref TreeIter iter, /* ref TreeIter */ IntPtr parent) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.IterChildren (out iter, TreeIter.New (parent));
+    }
+
+    internal static bool TreeModelIterHasChildImpl (IntPtr tree_model, /* ref TreeIter */ IntPtr iter) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.IterHasChild (TreeIter.New (iter));
+    }
+
+    internal static int TreeModelIterNChildrenImpl (IntPtr tree_model, /* ref TreeIter */ IntPtr iter) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.IterNChildren (TreeIter.New (iter));
+    }
+
+    internal static bool TreeModelIterNthChildImpl (IntPtr tree_model, out TreeIter iter, /* ref TreeIter */ IntPtr parent, int n) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.IterNthChild (out iter, TreeIter.New (parent), n);
+    }
+
+    internal static bool TreeModelIterParentImpl (IntPtr tree_model, ref TreeIter iter, ref TreeIter child) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      return tm.IterParent (out iter, child);
+    }
+
+    internal static void TreeModelRefNodeImpl (IntPtr tree_model, ref TreeIter iter) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      tm.RefNode (iter);
+    }
+
+    internal static void TreeModelUnrefNodeImpl (IntPtr tree_model, ref TreeIter iter) {
+      Gtk.TreeModel tm = (Gtk.TreeModel) GLib.Object.GetObject (tree_model, false);
+      tm.UnrefNode (iter);
+    }
+
+    public ManagedTreeModel ()
+      : base (ManagedTreeModelGetType ())
+    {
+    }
+
+    public ManagedTreeModel (IntPtr handle)
+      : base (handle)
+    {
+    }
+
+  }
+
+}
--- /dev/null	2004-02-23 13:02:56.000000000 -0800
+++ sample/ManagedModelDemo.cs	2004-05-24 15:33:06.220967952 -0700
@@ -0,0 +1,81 @@
+using System;
+
+using Gtk;
+
+public class SampleTreeModel : ManagedTreeModel {
+  public SampleTreeModel () {
+  }
+
+  public override int NColumns {
+    get {
+      return 2;
+    }
+  }
+
+  public override Type ColumnType (int index) {
+    return typeof(string);
+  }
+
+  public override bool GetIter (out Gtk.TreeIter iter, Gtk.TreePath path) {
+    iter = TreeIter.Zero;
+
+    if (path == null)
+      return false;
+
+    if (path.Indices.Length != 1)
+      return false;
+
+    iter.Stamp = 100;
+    if (path.Indices[0] < 10) {
+      iter.UserData1 = (IntPtr) path.Indices[0];
+      return true;
+    }
+
+    return false;
+  }
+
+  public override Gtk.TreePath GetPath (Gtk.TreeIter iter) {
+    TreePath path = new TreePath ();
+    path.PrependIndex ((int) iter.UserData1);
+    return path;
+  }
+
+  public override object GetValue (Gtk.TreeIter iter, int column) {
+    int row = (int) iter.UserData1;
+    return String.Format ("Row {0} Column {1}", row, column);
+  }
+
+  public override bool IterNext (ref Gtk.TreeIter iter) {
+    int row = (int) iter.UserData1;
+    if (row < 10) {
+      iter.UserData1 = (IntPtr) (row + 1);
+      return true;
+    } else {
+      iter = TreeIter.Zero;
+      return false;
+    }
+  }
+}
+
+public class ManagedModelDemo {
+
+  public static void Main () {
+    Application.Init();
+
+    Window w = new Window("Managed Model Demo");
+    w.SetDefaultSize (500, 300);
+
+    ScrolledWindow sw = new ScrolledWindow ();
+
+    SampleTreeModel stm = new SampleTreeModel();
+    Console.WriteLine ("Stm Handle: {0}", ((int) stm.Handle).ToString("x"));
+    TreeView tv = new TreeView (stm);
+    tv.AppendColumn ("One", new Gtk.CellRendererText(), "text", 0);
+    tv.AppendColumn ("Two", new Gtk.CellRendererText(), "text", 1);
+    sw.Add (tv);
+    w.Add (sw);
+    w.ShowAll ();
+
+    Application.Run();
+  }
+}

--------------040605080500060008070605--