Nooo! It’s that GtkTreeView proxy guy again!

And I’m not finished with the GtkTreeView. No I’m not. Moehaha!

I created this full sample that shows what I meant with custom treemodels and only allocating the model items behind visible rows. It includes an autotools environment and more or less good way of creating classes in C (except that I didn’t yet use GObject for MsgHeader nor MsgHeaderProxy, feel free to send me a diff).
This is a Subversion repository. Use “svn checkout” in front of the url after installing subversion.

It uses the “unref_node” method of the GtkTreeModelIface interface which gets triggered by gtk_tree_model_unref_node to unallocate the real subjects that aren’t visible in the view.

I noticed that it (it is the GtkTreeView stuff) sometimes “misses” rows that become invisible (if you scroll very fast). So I fear this unref_node method will need fixes and/or if you use it, you’ll need to also create a background thread/procedure that checks for leftovers. This sample shows how you can walk the entire treemodel and do things with only the unvisible ones. I know it’s ugly. IMHO the full demo isn’t, but regretfully doesn’t the unref_node stuff work perfectly.

Feel free to request SVN accounts and/or send diffs if you want to experiment.

Good morning and by the way

Good morning (for people in Europe, of course) .. and by the way. About that GtkTreeView sample of last night:

Say you wanted to use a string value of the subject as a row-value in a column of such a treeview? I didn’t show that yesterday. You can do that by converting it to a GValue and setting that as the “text” property of the cell. You do it like this:

static void
msg_header_treeview_get_model_item (GtkTreeViewColumn *tree_c,
                                   GtkCellRenderer *cell,
				   GtkTreeModel *tree_m,
                                   GtkTreeIter *iter, gpointer data)
{
	GValue val = {0,};
	IMsgHeader *header;

	gtk_tree_model_get (tree_m, iter, COLUMN_HEADER,
			&header, -1);
	g_value_init (&val, G_TYPE_STRING);
	g_value_set_string (&val,
		imsg_header_get_from (header));
	g_object_set_property (G_OBJECT (cell), "text", &val);
	g_value_unset (&val);
}

  gtk_tree_view_column_set_cell_data_func (column, renderer,
	msg_header_treeview_get_model_item, NULL, ...);

What will happen? The proxy classes will be instantiated. Yes, all of them. If you don’t want that to happen, you will need to create a custom GtkTreeModel implementation or use ETable, which is available in gal. Evolution also uses the ETable widget and it’s models for displaying the headers of your big INBOX. However, the proxy classes are rather small. I didn’t do it here, but if you want to avoid memory segmentation, there’s tools in glib (memory pools, etc) for allocating lots of such instances. Or simply use the amount as second argument of the g_new function and increase your pointer each iteration (this causes a large block of memory, this is likely going to be less or not segmented. Doing 10.000 times g_new(MsgHeaderPrxy,1) will cause memory segmentation and you don’t want that).

In the sample case only a g_strdup is happening in the real subject instantiation. In reality it’s often far worse. Don’t change your model items: View and Model should be decoupled.

In stead, you simply create proxy classes for it. The first time those are needed (when their rows become visible in the treeview, for example. As one of it’s values are now used to draw the treeview rows themselves), they will instantiate the real subject and use that to deliver the requested property. Note that this “first time they become visible”-behaviour is only valid for GtkTreeView when the fixed-height of the treeview widget and the fixed-width of the column properties are set. Else a background procedure will fetch all to calculate the scrollbar (ask kris and jrb on IRC for more details about this).

You are, of course, responsible for cleaning them up (also that, I didn’t show). You could, for example, in GObject overload the destroy and check for this->real not being NULL, and free it if that is the case. There’s also other methods (a factory that caches the real subject instances and always gives the same instance in case you have the same id multiple times in your list model: in this case, freeing up the real subject instances might get more complicated). This depends on your application design, of course.

I’m now searching for a technique to auto-free the real subjects behind the rows that aren’t visible. If you know: tell me :-p. Note that when using something like this, you want to use a memory pool for the real subjects (else: possible memory segmentation).