Re: ideas on improving the performance of gtk_tree_view



Hi,

Lainaus Federico Mena Quintero <federico ximian com>:

> Exactly.  GtkListStore is implemented as a GSequence (a splay tree),
> where each node is one row in the list.  Then, the data for the row's
> columns is stored in a linked list (GtkTreeDataList).  You could
> reimplement GtkTreeDataList in terms of an array and get a good speedup
> for *all* uses of GtkListStore (i.e. you'd be replacing a dominant
> O(n^2) for get/set operations in the list store with a simpler O(log n)
> for splay tree lookups, plus the constant time to access a column within
> a node).
> 
> Using an array instead of a linked list for GtkTreeDataList is a great
> idea, and we should definitely review a patch for that :)

I tried this idea and changed the GtkTreeDataList to be an array instead of
linked list (see the attached patch, made against svn head). The original
testcase (5000x50 model) started up faster (but was still slow), but I didn't do
any actual measurements yet (let's see tomorrow ;)

I made the following changes:
 * Added dimension/index parameter to many GtkTreeDataList calls (I understood 
   that this API was OK to be changed). The GtkTreeDataList is now an array of
   n elements instead of single list node.
 * GtkListStore and GtkTreeStore needed similar patches, including:
   Simpler get_value/set_value implementation, because we know that the
   datalist will contain n elements and they can be indexed easily.
 * Drag'n'drop code now uses simpler _gtk_tree_data_list_copy (I renamed 
   _gtk_tree_data_list_node_copy, since we now have more than one element).

-Markku-
Index: gtk/gtktreestore.c
===================================================================
--- gtk/gtktreestore.c	(revision 17562)
+++ gtk/gtktreestore.c	(working copy)
@@ -386,8 +386,11 @@
 node_free (GNode *node, gpointer data)
 {
   if (node->data)
-    _gtk_tree_data_list_free (node->data, (GType*)data);
-  node->data = NULL;
+  {
+    GtkTreeStore *store = GTK_TREE_STORE(data);
+    _gtk_tree_data_list_free (node->data, store->column_headers, store->n_columns);
+    node->data = NULL;
+  }
 
   return FALSE;
 }
@@ -398,7 +401,7 @@
   GtkTreeStore *tree_store = GTK_TREE_STORE (object);
 
   g_node_traverse (tree_store->root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
-		   node_free, tree_store->column_headers);
+		   node_free, tree_store);
   g_node_destroy (tree_store->root);
   _gtk_tree_data_list_header_free (tree_store->sort_list);
   g_free (tree_store->column_headers);
@@ -557,20 +560,17 @@
 {
   GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
   GtkTreeDataList *list;
-  gint tmp_column = column;
 
   g_return_if_fail (column < tree_store->n_columns);
   g_return_if_fail (VALID_ITER (iter, tree_store));
 
   list = G_NODE (iter->user_data)->data;
 
-  while (tmp_column-- > 0 && list)
-    list = list->next;
-
   if (list)
     {
       _gtk_tree_data_list_node_to_value (list,
 					 tree_store->column_headers[column],
+					 column,
 					 value);
     }
   else
@@ -719,8 +719,6 @@
 			       gboolean      sort)
 {
   GtkTreeDataList *list;
-  GtkTreeDataList *prev;
-  gint old_column = column;
   GValue real_value = {0, };
   gboolean converted = FALSE;
   gboolean retval = FALSE;
@@ -748,61 +746,23 @@
       converted = TRUE;
     }
 
-  prev = list = G_NODE (iter->user_data)->data;
-
-  while (list != NULL)
+  list = G_NODE (iter->user_data)->data;
+  if (G_UNLIKELY(list == NULL))
     {
-      if (column == 0)
-	{
+      G_NODE (iter->user_data)->data = list = 
+          _gtk_tree_data_list_alloc (tree_store->n_columns);
+    }
+
 	  if (converted)
-	    _gtk_tree_data_list_value_to_node (list, &real_value);
+	    _gtk_tree_data_list_value_to_node (list, column, &real_value);
 	  else
-	    _gtk_tree_data_list_value_to_node (list, value);
+	    _gtk_tree_data_list_value_to_node (list, column, value);
 	  retval = TRUE;
 	  if (converted)
 	    g_value_unset (&real_value);
           if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
-            gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
+            gtk_tree_store_sort_iter_changed (tree_store, iter, column, TRUE);
 	  return retval;
-	}
-
-      column--;
-      prev = list;
-      list = list->next;
-    }
-
-  if (G_NODE (iter->user_data)->data == NULL)
-    {
-      G_NODE (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
-      list->next = NULL;
-    }
-  else
-    {
-      list = prev->next = _gtk_tree_data_list_alloc ();
-      list->next = NULL;
-    }
-
-  while (column != 0)
-    {
-      list->next = _gtk_tree_data_list_alloc ();
-      list = list->next;
-      list->next = NULL;
-      column --;
-    }
-
-  if (converted)
-    _gtk_tree_data_list_value_to_node (list, &real_value);
-  else
-    _gtk_tree_data_list_value_to_node (list, value);
-  
-  retval = TRUE;
-  if (converted)
-    g_value_unset (&real_value);
-
-  if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
-    gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
-
-  return retval;
 }
 
 /**
@@ -1013,7 +973,7 @@
 
   if (G_NODE (iter->user_data)->data)
     g_node_traverse (G_NODE (iter->user_data), G_POST_ORDER, G_TRAVERSE_ALL,
-		     -1, node_free, tree_store->column_headers);
+		     -1, node_free, tree_store);
 
   path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
   g_node_destroy (G_NODE (iter->user_data));
@@ -1791,31 +1751,11 @@
                 GtkTreeIter  *dest_iter)
 {
   GtkTreeDataList *dl = G_NODE (src_iter->user_data)->data;
-  GtkTreeDataList *copy_head = NULL;
-  GtkTreeDataList *copy_prev = NULL;
-  GtkTreeDataList *copy_iter = NULL;
   GtkTreePath *path;
-  gint col;
 
-  col = 0;
-  while (dl)
-    {
-      copy_iter = _gtk_tree_data_list_node_copy (dl, tree_store->column_headers[col]);
+  G_NODE (dest_iter->user_data)->data = _gtk_tree_data_list_copy(dl, 
+          tree_store->column_headers, tree_store->n_columns);
 
-      if (copy_head == NULL)
-        copy_head = copy_iter;
-
-      if (copy_prev)
-        copy_prev->next = copy_iter;
-
-      copy_prev = copy_iter;
-
-      dl = dl->next;
-      ++col;
-    }
-
-  G_NODE (dest_iter->user_data)->data = copy_head;
-
   path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), dest_iter);
   gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, dest_iter);
   gtk_tree_path_free (path);
Index: gtk/gtktreedatalist.c
===================================================================
--- gtk/gtktreedatalist.c	(revision 17562)
+++ gtk/gtktreedatalist.c	(working copy)
@@ -28,38 +28,30 @@
 /* node allocation
  */
 GtkTreeDataList *
-_gtk_tree_data_list_alloc (void)
+_gtk_tree_data_list_alloc (gint n)
 {
-  GtkTreeDataList *list;
-
-  list = g_slice_new0 (GtkTreeDataList);
-
-  return list;
+  return g_slice_alloc0(sizeof(GtkTreeDataList) * n);
 }
 
 void
 _gtk_tree_data_list_free (GtkTreeDataList *list,
-			  GType           *column_headers)
+			  GType           *column_headers, gint n)
 {
-  GtkTreeDataList *tmp, *next;
-  gint i = 0;
+  gpointer p;
+  gint i;
 
-  tmp = list;
-
-  while (tmp)
+  for (i = 0; i < n; i++)
+    if ( (p = list[i].data.v_pointer) != NULL)
     {
-      next = tmp->next;
       if (g_type_is_a (column_headers [i], G_TYPE_STRING))
-	g_free ((gchar *) tmp->data.v_pointer);
-      else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT) && tmp->data.v_pointer != NULL)
-	g_object_unref (tmp->data.v_pointer);
-      else if (g_type_is_a (column_headers [i], G_TYPE_BOXED) && tmp->data.v_pointer != NULL)
-	g_boxed_free (column_headers [i], (gpointer) tmp->data.v_pointer);
-
-      g_slice_free (GtkTreeDataList, tmp);
-      i++;
-      tmp = next;
+        g_free (p);
+      else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT))
+        g_object_unref (p);
+      else if (g_type_is_a (column_headers [i], G_TYPE_BOXED))
+        g_boxed_free (column_headers [i], p);
     }
+
+  g_slice_free1(sizeof(GtkTreeDataList) * n, list);
 }
 
 gboolean
@@ -118,7 +110,7 @@
 }
 void
 _gtk_tree_data_list_node_to_value (GtkTreeDataList *list,
-				   GType            type,
+				   GType            type, gint index,
 				   GValue          *value)
 {
   g_value_init (value, type);
@@ -126,55 +118,55 @@
   switch (get_fundamental_type (type))
     {
     case G_TYPE_BOOLEAN:
-      g_value_set_boolean (value, (gboolean) list->data.v_int);
+      g_value_set_boolean (value, (gboolean) list[index].data.v_int);
       break;
     case G_TYPE_CHAR:
-      g_value_set_char (value, (gchar) list->data.v_char);
+      g_value_set_char (value, (gchar) list[index].data.v_char);
       break;
     case G_TYPE_UCHAR:
-      g_value_set_uchar (value, (guchar) list->data.v_uchar);
+      g_value_set_uchar (value, (guchar) list[index].data.v_uchar);
       break;
     case G_TYPE_INT:
-      g_value_set_int (value, (gint) list->data.v_int);
+      g_value_set_int (value, (gint) list[index].data.v_int);
       break;
     case G_TYPE_UINT:
-      g_value_set_uint (value, (guint) list->data.v_uint);
+      g_value_set_uint (value, (guint) list[index].data.v_uint);
       break;
     case G_TYPE_LONG:
-      g_value_set_long (value, list->data.v_long);
+      g_value_set_long (value, list[index].data.v_long);
       break;
     case G_TYPE_ULONG:
-      g_value_set_ulong (value, list->data.v_ulong);
+      g_value_set_ulong (value, list[index].data.v_ulong);
       break;
     case G_TYPE_INT64:
-      g_value_set_int64 (value, list->data.v_int64);
+      g_value_set_int64 (value, list[index].data.v_int64);
       break;
     case G_TYPE_UINT64:
-      g_value_set_uint64 (value, list->data.v_uint64);
+      g_value_set_uint64 (value, list[index].data.v_uint64);
       break;
     case G_TYPE_ENUM:
-      g_value_set_enum (value, list->data.v_int);
+      g_value_set_enum (value, list[index].data.v_int);
       break;
     case G_TYPE_FLAGS:
-      g_value_set_flags (value, list->data.v_uint);
+      g_value_set_flags (value, list[index].data.v_uint);
       break;
     case G_TYPE_FLOAT:
-      g_value_set_float (value, (gfloat) list->data.v_float);
+      g_value_set_float (value, (gfloat) list[index].data.v_float);
       break;
     case G_TYPE_DOUBLE:
-      g_value_set_double (value, (gdouble) list->data.v_double);
+      g_value_set_double (value, (gdouble) list[index].data.v_double);
       break;
     case G_TYPE_STRING:
-      g_value_set_string (value, (gchar *) list->data.v_pointer);
+      g_value_set_string (value, (gchar *) list[index].data.v_pointer);
       break;
     case G_TYPE_POINTER:
-      g_value_set_pointer (value, (gpointer) list->data.v_pointer);
+      g_value_set_pointer (value, (gpointer) list[index].data.v_pointer);
       break;
     case G_TYPE_BOXED:
-      g_value_set_boxed (value, (gpointer) list->data.v_pointer);
+      g_value_set_boxed (value, (gpointer) list[index].data.v_pointer);
       break;
     case G_TYPE_OBJECT:
-      g_value_set_object (value, (GObject *) list->data.v_pointer);
+      g_value_set_object (value, (GObject *) list[index].data.v_pointer);
       break;
     default:
       g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
@@ -184,65 +176,65 @@
 
 void
 _gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
-				   GValue          *value)
+           gint index, GValue          *value)
 {
   switch (get_fundamental_type (G_VALUE_TYPE (value)))
     {
     case G_TYPE_BOOLEAN:
-      list->data.v_int = g_value_get_boolean (value);
+      list[index].data.v_int = g_value_get_boolean (value);
       break;
     case G_TYPE_CHAR:
-      list->data.v_char = g_value_get_char (value);
+      list[index].data.v_char = g_value_get_char (value);
       break;
     case G_TYPE_UCHAR:
-      list->data.v_uchar = g_value_get_uchar (value);
+      list[index].data.v_uchar = g_value_get_uchar (value);
       break;
     case G_TYPE_INT:
-      list->data.v_int = g_value_get_int (value);
+      list[index].data.v_int = g_value_get_int (value);
       break;
     case G_TYPE_UINT:
-      list->data.v_uint = g_value_get_uint (value);
+      list[index].data.v_uint = g_value_get_uint (value);
       break;
     case G_TYPE_LONG:
-      list->data.v_long = g_value_get_long (value);
+      list[index].data.v_long = g_value_get_long (value);
       break;
     case G_TYPE_ULONG:
-      list->data.v_ulong = g_value_get_ulong (value);
+      list[index].data.v_ulong = g_value_get_ulong (value);
       break;
     case G_TYPE_INT64:
-      list->data.v_int64 = g_value_get_int64 (value);
+      list[index].data.v_int64 = g_value_get_int64 (value);
       break;
     case G_TYPE_UINT64:
-      list->data.v_uint64 = g_value_get_uint64 (value);
+      list[index].data.v_uint64 = g_value_get_uint64 (value);
       break;
     case G_TYPE_ENUM:
-      list->data.v_int = g_value_get_enum (value);
+      list[index].data.v_int = g_value_get_enum (value);
       break;
     case G_TYPE_FLAGS:
-      list->data.v_uint = g_value_get_flags (value);
+      list[index].data.v_uint = g_value_get_flags (value);
       break;
     case G_TYPE_POINTER:
-      list->data.v_pointer = g_value_get_pointer (value);
+      list[index].data.v_pointer = g_value_get_pointer (value);
       break;
     case G_TYPE_FLOAT:
-      list->data.v_float = g_value_get_float (value);
+      list[index].data.v_float = g_value_get_float (value);
       break;
     case G_TYPE_DOUBLE:
-      list->data.v_double = g_value_get_double (value);
+      list[index].data.v_double = g_value_get_double (value);
       break;
     case G_TYPE_STRING:
-      g_free (list->data.v_pointer);
-      list->data.v_pointer = g_value_dup_string (value);
+      g_free (list[index].data.v_pointer);
+      list[index].data.v_pointer = g_value_dup_string (value);
       break;
     case G_TYPE_OBJECT:
-      if (list->data.v_pointer)
-	g_object_unref (list->data.v_pointer);
-      list->data.v_pointer = g_value_dup_object (value);
+      if (list[index].data.v_pointer)
+	g_object_unref (list[index].data.v_pointer);
+      list[index].data.v_pointer = g_value_dup_object (value);
       break;
     case G_TYPE_BOXED:
-      if (list->data.v_pointer)
-	g_boxed_free (G_VALUE_TYPE (value), list->data.v_pointer);
-      list->data.v_pointer = g_value_dup_boxed (value);
+      if (list[index].data.v_pointer)
+	g_boxed_free (G_VALUE_TYPE (value), list[index].data.v_pointer);
+      list[index].data.v_pointer = g_value_dup_boxed (value);
       break;
     default:
       g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
@@ -251,17 +243,18 @@
 }
 
 GtkTreeDataList *
-_gtk_tree_data_list_node_copy (GtkTreeDataList *list,
-                               GType            type)
+_gtk_tree_data_list_copy (GtkTreeDataList *list,
+                          GType *types, gint n)
 {
   GtkTreeDataList *new_list;
-
+  gint i;
+  
   g_return_val_if_fail (list != NULL, NULL);
   
-  new_list = _gtk_tree_data_list_alloc ();
-  new_list->next = NULL;
-
-  switch (get_fundamental_type (type))
+  new_list = _gtk_tree_data_list_alloc (n);
+  
+  for (i = 0; i < n; i++)
+    switch (get_fundamental_type (types[i]))
     {
     case G_TYPE_BOOLEAN:
     case G_TYPE_CHAR:
@@ -277,25 +270,25 @@
     case G_TYPE_POINTER:
     case G_TYPE_FLOAT:
     case G_TYPE_DOUBLE:
-      new_list->data = list->data;
+      new_list[i].data = list[i].data;
       break;
     case G_TYPE_STRING:
-      new_list->data.v_pointer = g_strdup (list->data.v_pointer);
+      new_list[i].data.v_pointer = g_strdup (list[i].data.v_pointer);
       break;
     case G_TYPE_OBJECT:
     case G_TYPE_INTERFACE:
-      new_list->data.v_pointer = list->data.v_pointer;
-      if (new_list->data.v_pointer)
-	g_object_ref (new_list->data.v_pointer);
+      new_list[i].data.v_pointer = list[i].data.v_pointer;
+      if (new_list[i].data.v_pointer)
+	g_object_ref (new_list[i].data.v_pointer);
       break;
     case G_TYPE_BOXED:
-      if (list->data.v_pointer)
-	new_list->data.v_pointer = g_boxed_copy (type, list->data.v_pointer);
+      if (list[i].data.v_pointer)
+	new_list[i].data.v_pointer = g_boxed_copy (types[i], list[i].data.v_pointer);
       else
-	new_list->data.v_pointer = NULL;
+	new_list[i].data.v_pointer = NULL;
       break;
     default:
-      g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
+      g_warning ("Unsupported node type (%s) copied.", g_type_name (types[i]));
       break;
     }
 
Index: gtk/gtkliststore.c
===================================================================
--- gtk/gtkliststore.c	(revision 17562)
+++ gtk/gtkliststore.c	(working copy)
@@ -455,21 +455,18 @@
 {
   GtkListStore *list_store = (GtkListStore *) tree_model;
   GtkTreeDataList *list;
-  gint tmp_column = column;
 
   g_return_if_fail (column < list_store->n_columns);
   g_return_if_fail (VALID_ITER (iter, list_store));
 		    
   list = g_sequence_get (iter->user_data);
 
-  while (tmp_column-- > 0 && list)
-    list = list->next;
-
   if (list == NULL)
     g_value_init (value, list_store->column_headers[column]);
   else
     _gtk_tree_data_list_node_to_value (list,
 				       list_store->column_headers[column],
+				       column, 
 				       value);
 }
 
@@ -564,8 +561,6 @@
 			       gboolean      sort)
 {
   GtkTreeDataList *list;
-  GtkTreeDataList *prev;
-  gint old_column = column;
   GValue real_value = {0, };
   gboolean converted = FALSE;
   gboolean retval = FALSE;
@@ -593,62 +588,24 @@
       converted = TRUE;
     }
 
-  prev = list = g_sequence_get (iter->user_data);
+  list = g_sequence_get (iter->user_data);
+  
+  if (G_UNLIKELY(list == NULL))
+  {
+    list = _gtk_tree_data_list_alloc(list_store->n_columns);
+    g_sequence_set (iter->user_data, list);
+  }
 
-  while (list != NULL)
-    {
-      if (column == 0)
-	{
-	  if (converted)
-	    _gtk_tree_data_list_value_to_node (list, &real_value);
-	  else
-	    _gtk_tree_data_list_value_to_node (list, value);
-	  retval = TRUE;
-	  if (converted)
-	    g_value_unset (&real_value);
-         if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
-            gtk_list_store_sort_iter_changed (list_store, iter, old_column);
-	  return retval;
-	}
-
-      column--;
-      prev = list;
-      list = list->next;
-    }
-
-  if (g_sequence_get (iter->user_data) == NULL)
-    {
-      list = _gtk_tree_data_list_alloc();
-      g_sequence_set (iter->user_data, list);
-      list->next = NULL;
-    }
-  else
-    {
-      list = prev->next = _gtk_tree_data_list_alloc ();
-      list->next = NULL;
-    }
-
-  while (column != 0)
-    {
-      list->next = _gtk_tree_data_list_alloc ();
-      list = list->next;
-      list->next = NULL;
-      column --;
-    }
-
   if (converted)
-    _gtk_tree_data_list_value_to_node (list, &real_value);
+    _gtk_tree_data_list_value_to_node (list, column, &real_value);
   else
-    _gtk_tree_data_list_value_to_node (list, value);
+    _gtk_tree_data_list_value_to_node (list, column, value);
 
-  retval = TRUE;
-  if (converted)
+	if (converted)
     g_value_unset (&real_value);
-
   if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
-    gtk_list_store_sort_iter_changed (list_store, iter, old_column);
-
-  return retval;
+    gtk_list_store_sort_iter_changed (list_store, iter, column);
+  return TRUE;
 }
 
 
@@ -857,7 +814,8 @@
   ptr = iter->user_data;
   next = g_sequence_iter_next (ptr);
   
-  _gtk_tree_data_list_free (g_sequence_get (ptr), list_store->column_headers);
+  _gtk_tree_data_list_free (g_sequence_get (ptr), 
+    list_store->column_headers, list_store->n_columns);
   g_sequence_remove (iter->user_data);
 
   list_store->length--;
@@ -1205,32 +1163,11 @@
       if (retval)
         {
           GtkTreeDataList *dl = g_sequence_get (src_iter.user_data);
-          GtkTreeDataList *copy_head = NULL;
-          GtkTreeDataList *copy_prev = NULL;
-          GtkTreeDataList *copy_iter = NULL;
 	  GtkTreePath *path;
-          gint col;
 
-          col = 0;
-          while (dl)
-            {
-              copy_iter = _gtk_tree_data_list_node_copy (dl,
-                                                         list_store->column_headers[col]);
-
-              if (copy_head == NULL)
-                copy_head = copy_iter;
-
-              if (copy_prev)
-                copy_prev->next = copy_iter;
-
-              copy_prev = copy_iter;
-
-              dl = dl->next;
-              ++col;
-            }
-
 	  dest_iter.stamp = list_store->stamp;
-          g_sequence_set (dest_iter.user_data, copy_head);
+          g_sequence_set (dest_iter.user_data, _gtk_tree_data_list_copy(dl, 
+            list_store->column_headers, list_store->n_columns));          
 
 	  path = gtk_list_store_get_path (tree_model, &dest_iter);
 	  gtk_tree_model_row_changed (tree_model, path, &dest_iter);
Index: gtk/gtktreedatalist.h
===================================================================
--- gtk/gtktreedatalist.h	(revision 17562)
+++ gtk/gtktreedatalist.h	(working copy)
@@ -28,8 +28,6 @@
 typedef struct _GtkTreeDataList GtkTreeDataList;
 struct _GtkTreeDataList
 {
-  GtkTreeDataList *next;
-
   union {
     gint	   v_int;
     gint8          v_char;
@@ -53,18 +51,18 @@
   GtkDestroyNotify destroy;
 } GtkTreeDataSortHeader;
 
-GtkTreeDataList *_gtk_tree_data_list_alloc          (void);
+GtkTreeDataList *_gtk_tree_data_list_alloc          (gint n);
 void             _gtk_tree_data_list_free           (GtkTreeDataList *list,
-						     GType           *column_headers);
+						     GType           *column_headers, gint n);
 gboolean         _gtk_tree_data_list_check_type     (GType            type);
 void             _gtk_tree_data_list_node_to_value  (GtkTreeDataList *list,
-						     GType            type,
+						     GType            type, gint index, 
 						     GValue          *value);
 void             _gtk_tree_data_list_value_to_node  (GtkTreeDataList *list,
-						     GValue          *value);
+						     gint index, GValue          *value);
 
-GtkTreeDataList *_gtk_tree_data_list_node_copy      (GtkTreeDataList *list,
-                                                     GType            type);
+GtkTreeDataList *_gtk_tree_data_list_copy      (GtkTreeDataList *list,
+                                                GType *types, gint n);
 
 /* Header code */
 gint                   _gtk_tree_data_list_compare_func (GtkTreeModel *model,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]