あおきです。

  In mail "[ruby-ext:00661] Re: (gtk) testgtk/ctree"
    Yasushi Shoji <yashi / yashi.com> wrote:

> > で、添付したパッチでどうでしょう。
> > グローバルなハッシュを使って、ノードに渡したデータだけを
> > リファレンスカウント風に管理してます。
> 
> まだ、patchを読んだだけなんですが、これだと同じ rowに同じ dataを入れると
> ref countだけ上がって、deleteの時に 消えないんじゃないでしょうか?

あ、確かに。
同じデータだけじゃなくて、上書きする場合は全部だめですね。
パッチ作り直しました。0.22 へのパッチです。

# そもそも、Gtk+側でポインタをクリアしてくれれば
# こんなことは問題にならないんでは
-------------------------------------------------------------------
あおきみねろう

--- org.ctree	Fri Dec  3 17:42:17 1999
+++ rbgtkctree.c	Sat Dec  4 00:10:32 1999
@@ -2,6 +2,7 @@
 
 static ID id_nodelist;
 
+/*
 static void
 ctree_node_mark(node)
      GtkCTreeNode *node;
@@ -9,13 +10,14 @@
     if (GTK_CTREE_ROW(node) && GTK_CTREE_ROW(node)->row.data)
 	rb_gc_mark(GTK_CTREE_ROW(node)->row.data);
 }
+*/
 
 VALUE
 make_ctree_node(node)
     GtkCTreeNode* node;
 {
     if (!node) return Qnil;
-    return Data_Wrap_Struct(gCTreeNode, ctree_node_mark, 0, node);
+    return Data_Wrap_Struct(gCTreeNode, 0, 0, node);
 }
 
 static GtkCTreeNode*
@@ -1101,13 +1103,60 @@
  *   node - tree node.
  *   data - custom data associated with a node.
  */
+
+static VALUE ctree_node_row_data;
+
+static void
+ctn_decref(data)
+    gpointer data;
+{
+    VALUE count;
+    int i;
+
+    /* decrement reference count */
+    count = rb_hash_aref(ctree_node_row_data, (VALUE)data);
+    if (!NIL_P(count)) return;
+    i = FIX2INT(count);
+    if (i == 1)
+	rb_funcall(ctree_node_row_data, rb_intern("delete"), 1, (VALUE)data);
+    else {
+        count = INT2FIX(i - 1);
+        rb_hash_aset(ctree_node_row_data, (VALUE)data, count);
+    }
+}
+
+static void
+ctn_incref(data)
+    gpointer data;
+{
+    VALUE count;
+
+    count = rb_hash_aref(ctree_node_row_data, (VALUE)data);
+    if (NIL_P(count))
+    	count = INT2FIX(1);
+    else {
+        int i;
+
+        i = FIX2INT(count) + 1;
+	count = INT2FIX(i);
+    }
+    rb_hash_aset(ctree_node_row_data, (VALUE)data, count);
+}
+    
 static VALUE
 ctree_node_set_row_data(self, node, data)
      VALUE self, node, data;
 {
-    gtk_ctree_node_set_row_data(GTK_CTREE(get_widget(self)),
-				get_ctree_node(node),
-				(gpointer)data);
+    GtkCTree *t;
+    GtkCTreeNode *n;
+    gpointer tmp;
+
+    t = GTK_CTREE(get_widget(self));
+    n = get_ctree_node(node);
+    if (tmp = gtk_ctree_node_get_row_data(t, n))
+        ctn_decref(tmp);
+    ctn_incref((gpointer)data);
+    gtk_ctree_node_set_row_data_full(t, n, (gpointer)data, ctn_decref);
     bind_ctree_node(self, node);
     return self;
 }
@@ -1532,6 +1581,9 @@
     rb_define_method(gCTree, "node_set_background", ctree_node_set_background, 2);
     rb_define_method(gCTree, "node_set_row_data", ctree_node_set_row_data, 2);
     rb_define_method(gCTree, "node_get_row_data", ctree_node_get_row_data, 1);
+    ctree_node_row_data = rb_hash_new();
+    rb_global_variable(&ctree_node_row_data);
+
     rb_define_method(gCTree, "node_moveto", ctree_node_moveto, 4);
     rb_define_method(gCTree, "node_is_visible?", ctree_node_is_visible_p, 1);
     rb_define_method(gCTree, "set_indent", ctree_set_indent, 1);