GtkTreeView ideas
This wiki page contains a bunch of ideas for improving GtkTreeView that I have collected over the years. Some of the ideas include work-in-progress patches. I do no longer plan to work on these patches, but perhaps some people are interested to pick up this work or use it as inspiration to improve other parts of the toolkit.
Even though the GtkTreeView codebase is often perceived as large and complicated (which it indeed is if you are new to it), I think the code base still has lots of potential. Many of the ideas below address shortcomings in GtkTreeView, unfortunately, often long-standing shortcomings. Resolving these shortcomings requires time, time that I unfortunately did not have available in the last few years.
July 2012, KristianRietveld
Contents
Layouting improvements
Layouting in GtkTreeView has been limited to a grid of rows and columns. It has always been very hard to have (slight) differences between rows, in particular if a completely different sets of GtkCellRenderers in two different rows is desired.
A couple of ideas are described to improve this situation. The last section provides another future perspective for GtkTreeView that resulted out of a brief discussion between BenjaminOtte and me at GUADEC 2011.
Refactoring GtkTreeView layouting code
To enable work on improving layouting, it is necessary to first refactor the core drawing code of GtkTreeView. The patch set for "extra space API", provided in the section below, contains quite some patches that form a first attempt to refactor GtkTreeView rendering into something that is easier to understand. These patches are by now very outdated due to changes in the drawing model in GTK+ 3 and the introduction of GtkCellArea. Some ideas still apply however and are still interesting and worth working on. Secondly, the extra space API work was based on this, so some understanding what was changed under the hood is useful to be able to understand the extra space API implementation.
We briefly describe the most important refactoring patches included with the "extra space API" code drop below. We refer to the patches by patch sequence number:
Patches 0-7,15 completely overhaul gtk_tree_view_bin_expose() (which in GTK+ 3 became gtk_tree_view_bin_draw()). bin_expose() is a very large function that is very hard to work with. These patches split bin_expose() into small functions, just handling one aspect of the bin_expose() operation. As a result, the code is much more self describing. A lot of local variables are used in bin_expose(), which are moved to a struct RenderContext that is being passed around.
This was found to be a worthwhile approach and these patches were consolidated into a single patch in 2009. See subsection "improved refactorings" below.
Patches 8-14 introduce a "CellWalker" in GtkTreeViewColumn in order to clean up the GtkTreeViewColumn code and especially remove gtk_tree_view_column_cell_process_action(). Since these patches were written, GtkCellArea has been developed and upstreamed which pretty much serves the same purpose.
Patches 17,24 remove macros for obtaining row height, location, etc. and moves these computations to functions. Effectively, this creates a layer between tree view and its RB tree, such that various parts of GtkTreeView no longer directly access the RB tree. This makes it easier to poke around. These patches are important to be able to understand the implementation of the extra space API below.
- Patch 18 splits up gtk_tree_view_button_press(), also for this an improved patch was written, see below.
Improved refactorings
For some of the attempted refactorings in the extra space API patch set, improved versions were written, with the intention of upstreaming these. These refactorings are:
Patch 1: refactor gtk_tree_view_bin_expose() using struct RenderContext as outlined above. Even though we now have gtk_tree_view_bin_draw() in GTK+ 3, the ideas still apply.
- Patch 2: bring gtk_tree_view_create_row_drag_icon() in sync with the expose routine.
- Patch 4: split up gtk_tree_view_button_press().
- Patch 5: introduce utility functions for looping over columns.
Patch 3 has been omitted from this patch series. You can find these improved patches here gtk-tree-refactor-dec2009.tar.gz.
Extra space API (has work-in-progress patch)
One of the big missing features is the ability to have group headers. Group headers typically spread over the entire row. Since such column spanning is not supported with cell renderers (see e.g. #309474), it is hard to implement this currently. GtkTreeView does have the capability of drawing separators which spread over the entire row (though, when multiple columns are active you clearly see that each column renders part of the separator, so it is not a true column spanning separator). Inspired by this, the extra space API takes this concept and abstracts it. The idea would be that the extra space API allows the user to draw custom content for a row and row separators can be implemented in terms of the extra space API.
At the core of the implementation of the extra space API is a change to the RB tree. We introduce the notion of "extra space" to RB nodes, such that extra space is added before or after the row content. It might seem awkward to do things this way. The rationale is the following: if extra space content are covering model rows, much like how row separators are implemented, they affect the parity computation and as a result affect row hinting.
The extra space API was prototyped on top of a first attempt to refactor the tree view code, as was discussed in the previous section. The implementation is found in the following patches:
Patches 17,24 abstract functions for obtaining row height, location. See also section "Refactoring GtkTreeView layouting code" above.
- Patch 25. Add support for extra_space/extra_offset to RB tree. An existing node can have extra space before or after the node. We deliberately do not introduce
a new node for extra space because that messes up the parity calculations used for row hinting.
- Patches 26,27. Implement extra space API.
- Patch 28. Introduce a new row separator API re-using the extra space API. This way, separators do not cover a model row and row hinting continues to work properly.
The full, work in progress, patch set is available from here gtk-tree-extra-space-API-jul2008.tar.gz.
Of course, the way extra space has been implemented could be seen as a hack and actually indicates how constrained the possibilities are for custom layouting in GtkTreeView.
Renderer objects
Renderer objects are an idea to make layouting more flexible. Currently, only GtkTreeViewColumns are capable of rendering tree view content. Even within GtkTreeViewColumn it is hard to have a different rendering scheme for different rows.
The basic idea of renderer objects is to abstract a renderer capable of rendering row content into a renderer object. When rendering contents, for each row a different renderer object can be used. By default, an implementation is provided of a renderer object that can render cell renderers in columns. This will also be used to achieve backwards compatibility. Separators, and also the extra space API described above, can be implemented as custom renderer objects. This could also open up the possibility to put generic widgets in a renderer object and put these in a GtkTreeView.
Generic container API
The idea for a generic container API is an extension of the ideas for renderer objects. Once ways to render row contents are abstracted into renderer objects, it, in theory, becomes possible to also design renderer objects that are able to render icon view items. What is still necessary is a different way to layout these renderer objects: so not strictly in rows, but also in grids.
Instead of having a separate GtkTreeView and GtkIconView, you would end up with a single GtkItemView. The GtkItemView implements all handling for item selections, keyboard navigation, mouse event handling (button press, button release), rubber banding, drag and drop. An interface is defined for layouting algorithms to implement. A GtkItemView instance is then combined with a class implementing the layouting interface, this will make GtkItemView layout the renderer objects. Renderer objects are still tied with rows from a GtkTreeModel.
In turn, GtkTreeView and GtkIconView can be reimplemented in terms of GtkItemView. This will eliminate a significant amount of code duplication, since GtkIconView and GtkTreeView have their own implementations of keyboard handling, mouse handling, drag and drop, etc., etc.
This way, GtkItemView would provide functionality to allow for:
Original GtkTreeView capability;
Original GtkItemView capability;
- "Windows File Selector"-style lists, now feasible through a specific layout class;
- etc.
What needs to be determined is how expanders and indentation that are currently present in GtkTreeView are handled. Perhaps this should be part of the renderer object and not of the layouting algorithm.
No-validation branch (has patch)
Validation is the process of measuring all rows that are visible in a GtkTreeView. The row's height is measured to be able to compute the full height of the tree view, which is required to get exact figures to set up the scroll bar. The width is used for sizing columns if the columns are configured to autosize or grow only.
The main problems with validation are that 1) it touches every (visible) row in the GtkTreeModel, which makes it close to impossible to write GtkTreeModel implementations which try to delay loading contents until the rows become visible on the screen; and 2) it is computationally expensive and can take a long time for large GtkTreeModels (validation is handled using an idle handler).
An exact scrollbar is actually not required. As soon as the size of the model in rows goes beyond 1000 to 10000 rows, it is impossible anyway to navigate to exactly the right row using the scrollbar. Therefore, estimated scrollbars are very likely good enough.
Instead of measuring every row, the approach of validation is changed to measure a representative subset of the rows (say 500 rows) and estimating the height of all rows based on that. This estimate is used to set up the scrollbars. Once the user starts scrolling and more rows become visible on the screen for the first time, the estimation is further refined. Note that when scrolling, all rows must be measured before they are painted to the screen for the first time. Also rows around the currently visible subset of rows must be measured for key navigation (e.g. handling of page up/down) to work correctly. A problem of this no-validation approach is that you can no longer guarantee that column contents will always fit when autosize is used, simply because not all rows are measured. Hopefully, such cases will not often occur due to the usage of a representative subset.
A work in progress patch implementing this can be found here gtk-tree-no-validation-jul2008.diff. There are a couple of corner cases left that still need fixing (some are marked with "FIXME"). With this patch, lists of 4 million rows can be handled with ease because there is no more UI lag due to all rows being validated in the background.
A Future Perspective for GtkTreeView
These thoughts are a summary of a conversation between BenjaminOtte and KristianRietveld at GUADEC 2011.
A big problem with GtkCellRenderer is that it replicates quite some stuff that is in GtkWidget. Think about size requisition, event handling and coordinating drawing. This has been manageable to some extent, but the virtually non-existent event handling in GtkCellRenderer has always been lacking. Now that width-for-height arrived in GTK+ 3.0, and drawing and event handling is being overhauled, it makes sense to reconsider GtkCellRenderer. Should we get rid of GtkCellRenderer and use widgets instead?
It is important to realize that GtkCellRenderers are re-used for each row that is being rendered in a GtkTreeView. This saves a lot of memory and bookkeeping, compared to for example instantiating GtkCellRenders for each separate row in the GtkTreeView.
An idea is to use GtkWidgets in a GtkTreeView instead of GtkCellRenders. GtkWidgets are instantiated only for rows which are currently visible. This means that we do not want to instantiate all widgets for row height measurement (a process known in the GtkTreeView source code known as validation). So, a first task is to move from validation to scroll bar estimation (see also the section on the "no-validation branch").
There are two approaches to contain widgets in a GtkTreeView. The first is to have a widget per (column, row) tuple. The second is to have a widget container per row. Let us name this container GtkRowContainer. The GtkRowContainer has child widgets for all (column, row) tuples and offsets for these widgets according to the column status. In GtkRowContainer we can then implement interesting things like column spanning. This is very hard to do in the current model because drawing and event handling are very quickly separated into the GtkTreeViewColumns.
When this has been accomplished, GtkCellArea is deprecated and removed.
Column attributes continue to exist and will simply map to widget properties instead of the current cell renderer properties.
In conjunction with this we might want to overhaul scrolling. When doing this, it might be desired to split the column headers out in a separate widget. An interface is then needed to connect the column headers to a tree view. See also the section on "flexible GtkTreeView headers".
Finally, it could be interesting to look into having a generic GtkItemView base class based on the above described model. This base class would implement drag-and-drop, selection of items, scrolling, key navigation, etc. GtkTreeView and GtkIconView then simply become, hopefully, tiny/thin subclasses of GtkItemView.
TreeModel improvements
TreeModel batch API
Every modification made to a GtkTreeModel has to be signaled to anybody observing this GtkTreeModel instance. Currently, a signal has to be sent for each individual modified row. This becomes a problem when large amounts of changes are made to the GtkTreeModel in a short period of time. Prime examples are clearing the entire model and filling the model from an idle handler with 500 to 1000 rows per idle handler callback.
An elegant solution to this problem is to introduce the possibility of batching together notifications of changes to a GtkTreeModel. Within this scheme, it would be possible to send a single row-inserted signal for a range of rows. Or, a single row-deleted is sent with as range of rows the entire tree model, which effectively clears the entire model (this is a way of implementing a "reset" signal that was sometimes proposed in discussions in the past #553008).
What the right way is to implement this is not yet clear. Two possible approaches are (which might actually both be needed):
- For the different signals, variants are introduced that are capable of designating a range of rows. So, e.g. a row-range-inserted signal is introduced, and so on.
- We adopt a kind of transactional approach. Two functions are introduced: gtk_tree_model_start_batch() and gtk_tree_model_finish_batch(). Once the start function has been called, we start collecting all signals to be emitted, but these signals are not emitted. When the finish function is called, these called signals would be passed to the observers with a single signal emission, by passing in a linked list of individual signals that would be emitted. However, for large models, this scheme would definitely benefit from having row-range-capable signals (imagine having a list of 2M row-deleted signals to clear a model).
Apart from the API issues, what is important to figure out is how these batch changes affect "modifier" models such as GtkTreeModelSort and GtkTreeModelFilter. In general, batch signals must still be in a certain order for the internal data structures of GtkTreeView, GtkTreeModelFilter, etc. to not go awry.
TreeModel lazy loading
For very large data sets, or data sets that are expensive to retrieve, one wants to avoid loading rows from such data sets as long as possible: that is, until a row is to be displayed on the screen. With very large data sets, most of the contents will never be viewed, so there is no use in fetching all data from the source.
The current implementation of the internal data structure in GtkTreeView makes such lazy loading very hard to implement. Once a model is registered with the GtkTreeView, the tree view will build the root level of its internal Red-Black Tree. This involves touching all nodes in the root level of the GtkTreeModel, as the reference count of each of these rows is incremented. The amount of rows to touch is simply determined by requesting the number of children in the root level. Furthermore, recall that the Red-Black tree is used to determine the total height of all rows present in the tree view.
Quite some rework of the GtkTreeView internals will be required to make lazy loading possible. Some thoughts:
GtkTreeModels need to start to distinguish between the total number of nodes available (or an estimate of this if not available!) and the number of nodes to be loaded into a view up front. The latter is used to fill the first part of the RB tree, the former is used to get an estimation of the total height of the tree for the scrollbars (see also the section on "no-validation", which is perhaps a prerequisite for this work).
- The assumptions that the RB tree always contains the entire root level of a model and that the entire root level of a model is referenced when attached to a view will no longer be true.
- There must be some way for the view to notify the model to load more nodes. A signal or callback functions to be called/emitted by the view should do here. The view is in the best position to determine whether or not to load more nodes, because it can monitor scrolling behavior where the model cannot.
This new model functionality should probably go into a new interface "GtkTreeModelLazyIface", which is only implemented by models providing support for lazy loading.
- When this additional interface is designed it has to be taken into account that a single model instance can have multiple observers. Thus, the model will have to listen for requests to load more nodes from multiple observers. This also implies that when more nodes are loaded (by request of one of the models), all models must be notified such that their internals and scrollbars can be updated.
Misc. GtkTreeView improvements
Cell editing problems
The current editing API, as defined by GtkCellEditable, has several design problems and is hard to use. This API is probably worth doing from scratch. One of the main problems is that no good distinction is made between canceling an edit operation and confirming the made changes. Because of this we are currently stuck picking one of two evils and that will never please everybody. Related bugs are for example #87811, #164494, #552902 (editing is canceled when a cell editable loses focus), 315280 (Cannot edit tree view cells with preedit window).
A very good summary of the problems, plus some ideas can be found in https://bugzilla.gnome.org/show_bug.cgi?id=315280#c8.
If this API is revamped, there should probably be separate signals for:
- User triggered a command to edit the current cell: show up an editing window now.
The editing widget changed state: we might want to update the model already (for example in the context of the combo box renderer, the original GtkCellEditable was never designed to properly handle this).
The user made the editing widget disappear: hide the editing widget, indicate whether this action was (or should be) a confirmation of the update or a cancellation, and update the model (if still needed).
The above is just a start. Before a good API can be designed, all scenarios must be thought out by looking at possible widgets that can be embedded and do editing. Widgets that are already in use include:
Entry: very straightforward, but people expect different "cancellation" policies. In some cases data should be confirmed on focus-out or Esc, in other cases it should not.
ComboBox: might want to have intermediate writes to the model. The GtkTreeView also needs support here for not stopping editing on
row-changed.
Spinner/popup range widget: same as ComboBox basically.
A study of scenarios will result in a concise list of desired behaviors. Possibly abstract these behaviors into "modes" and have API to select such a mode for a given editable cell renderer.
Revamp GtkTreeView Drag-and-Drop implementation (has-patch)
Ever since GtkTreeView was first introduced in GTK+ 2.0, one of the major missing features has been support for drag-and-drop of multiple items. This bug has been tracked in #70479.
Some interesting ideas for a TreeView Drag and Drop API are given by Federico Mena Quintero in the following e-mail https://mail.gnome.org/archives/gtk-devel-list/2004-February/msg00232.html.
Based on Federico's e-mail and my own ideas, I came up with the following list of requirements for a new GtkTreeview DnD API:
- Naturally, must be able to drag one or more items.
- Show the exact content of rows being dragged -- if not too large, otherwise use a custom drag cursor. Also allow people to override this
behavior.
Support dragging between different tree views and types of GtkTreeModels.
- Support dragging rows between different applications/processes.
- For trees, support drag and drop to/from another branch level.
- Possibly introduce a "rows-moved" signal. Currently, drag and drop is implemented by removing a row from a model and inserting it again. A "rows-moved" operation would make the insert/delete unnecessary and simply moves the row in the data structure.
The code handling the GtkTreeModel side of drag and drop should be fully widget-agnostic. This also holds true for any exposed interface. It then becomes possible to use the same interfaces for implementing drag-and-drop in other widgets that use GtkTreeModels.
- You want to allow drops on sorted lists if the data originates from other widgets. Also allow for moving items across levels in sorted trees.
- Preference of signals above interface (see above e-mail from Federico).
- Data to import/export should be configured inside the model.
Should have access to GdkDragContext to notify about legal drag actions.
- Available data types and drag actions depend on currently selected row.
Don't implement a GtkTreeDragSource::drag_data_get(), but simply re-use GtkWidget::drag_data_get(). Analog for ::drag_data_delete().
- The current API for row_drop_possible() is not sufficient. It cannot tell you where the user wants to drop the row (before/after/on).
A first design taking these issues into account is the following. To have a generic code for storing data to transfer (and to retrieve this) the GtkTreeModelDndSerializerIface is introduced. Several serializers can be implemented that support storing/retrieving data in different formats. A simple serializer is for example the one simply storing GtkTreePaths of the rows that are being moved. This data format can of course only be used when rows are moved inside the same tree view. A more sophisticated serializer can actually store full row contents. The serializer interface has methods to check whether certain selection targets are supported. Serializers can be shared amongst models that implement DnD support. So, when implementing your own model, you can re-use the serializer for transfer of Drag and drop rows, instead of re-implementing this.
Next, a new tree model DnD interface is needed that understands the concept of serializers and also improves upon the current tree model drag source and drag dest interfaces. This is the GtkTreeModelDndIface and is supposed to be implemented by all models that want to have drag-and-drop supported when displayed in a tree view (and in the future also icon view).
The drag-and-drop support has to be changed in GtkTreeView to support these new interfaces. Furthermore, new signals are introduced to test whether a drag can be started and whether data can be dropped at a given position.
A work in progress patch against a GTK+ 2.x from 2008 can be found here gtk-tree-new-dnd-28oct2008.diff. This patch is really a work in progress and is nowhere near finished. It implements the serializer and new DnD interface ideas outlined above. Secondly, it massively refactors GtkTreeView's drag and drop internals. Signals are used to test for whether a drag can be started and a drop can be performed at a certain position. Support for the new drag and drop interface is implemented, while compatibility with the old interfaces is maintained. Of course, if a model implements the new-style interface, this is preferred. Finally, the patch makes tree view capable of rendering a list of multiple rows as drag icon.
Problematic in the patch is that unfortunately testtreednd.c and gtktreemodelrowserializer.c are missing.
A couple of to do items for the work-in-progress drag and drop code are:
- How to properly handle trees? How does one store (serialize) hierarchies in selection data? Simply store the depth? Also store expansion state? When a node is moved, move its children as well.
- A compatible implementation of the old drag and drop API needs to be finished.
- Currently a "can-drop-rows" method is present. Is it useful to have a "can-drag-rows" method as well? (For example, you could use this to block certain rows (group headers) from being dragged).
- Tree view target lists need to be refreshed on gtk_tree_view_set_model().
Simple list API (has patch)
It has been often mentioned that setting up a simple, generic, list with GtkTreeView takes too much effort. Especially when compared to the old !GtkCList. To address this concern it is very viable to design a wrapper class, that simplifies creation and handling of simple generic lists.
Several GTK+ language bindings already contain such a class. Inspiration was sought in the Perl and Python bindings of GTK+, by means of a brief discussion with Emmanuele Bassi and Johan Dahlin at the GTK+ hackfest in 2008. From this discussion resulted a list of desired capabilities for such a simple wrapper class:
- Possibility of constructing a list with multiple columns. Columns are specified by GType, based on this type a cell renderer is automatically selected.
- Have simple signals for monitoring changes in selection or activation of rows.
- Simple functions for adding and removing rows.
- Straightforward helpers for manipulating the list's selection state.
- Possibility to configure some aspects of a column, for example configuring a column to be editable. Support for handling the edited callback for basic cell renderers such as the text renderer and toggle/check button renderer.
- Functions to make the list sortable, or make the columns resizeable.
Prototype patch against GTK+ 2 from 2008 is available, complete with an example demonstrating and testing the API gtk-simple-list-20sep2008.diff. On top of this, you want to apply the following patches: gtk-simple-list-01-handle-toggle-renderers.diff gtk-simple-list-02-remove-set-cell-renderer-stub.diff gtk-simple-list-03-add-new-with-titles-constructor.diff
Hidden selections and remember expanded nodes
GtkTreeView is not capable of doing the following:
Storing hidden selections, that is, maintaining selection state of nodes whose parent is collapsed (#80870).
- Storing expand/collapse state of nodes whose parent is collapsed. (In other words, expand node 1, expand nodes 1:1 and 1:2, collapse node 1,
expand node 1, nodes 1:1 and 1:2 are no longer expanded, their expand/collapse was forgotten). See #50054.
Both problems are related with each other since they are both caused by the way the Red-Black tree is used internally in GtkTreeView. Only nodes which are visible (i.e. their parent is expanded) are present in the Red-Black tree. As soon as a node is collapsed, all its children are removed from the RB tree.
It is clear that in order to fix this in an elegant way the usage of the Red-Black tree should be changed such that children of collapsed nodes are no longer evicted from the data structure. For hidden selections, the existing flags can be re-used. A new flags have to be introduced for a node's expand/collapse state, because currently the expand/collapse state is simply derived from the fact whether a node can have children and whether the child pointer is NULL. Determination of a node's expand/collapse state has to be reworked in all of the code.
A not so much elegant way to implement storage of expand/select state for hidden nodes is to simply store row references to expanded nodes when nodes are evicted from the RB tree. These states can be recovered when the parent is expanded again. This technique might not work for hidden selections, because for selections quite some statekeeping in the RB tree is involved.
Flexible GtkTreeView headers
Currently, it is very hard or basically impossible to have custom tree view headers. In general, one is restricted to buttons, or another kind of widgets, and the position of the header is constrained to the top of the GtkTreeView container.
There have been requests for more flexibility in the customization of tree view headers. The requests include the ability to draw custom content in the area between the header buttons and the row content (#382293). Another request is the possibility to have fully custom tree view headers, such that headers can be much more advanced than just a single button.
One way to accomplish this is by moving the header code out of GtkTreeView and GtkTreeViewColumn and turning this into a separate widget. The separate widget can be packed anywhere in the user interface. An interface is needed to link this separate widget and a GtkTreeView. Through this interface, GtkTreeView can communicate column properties such as: sizing type, whether the column is reorderable, column names, column width, whether the column is clickable or resizeable, a column's sort column id and sort order. The header widget will have to implement the possibility to resize and reorder columns. Changes in column order and size have to be communicated back to tree view, such that the row content can be updated.
The interface between GtkTreeView and the header widget should be clearly defined and become public API, such that custom header widgets can simply implement this interface in order to get things to work. Furthermore, it might be worthwhile to make sure it is possible to subclass the default header widget to avoid having to reimplement column resize/reorder/etc. for every header widget implementation.
Optimized gtk_tree_view_build_tree() variants
When a GtkTreeModel is set on a GtkTreeView, the first thing that happens is that GtkTreeView will walk over the model to set up the internal RB tree. This happens in the function gtk_tree_view_build_tree(), which contains a single generic loop. In a discussion with "dcouts" on the GTK+ IRC channel, it was noticed that this loop can be optimized for certain cases (in particular "is_list" models). By introducing additional variants of this loop, to be used in these certain cases when possible, considerable time could be saved when loading large GtkTreeModels into the tree view.
What appears possible on a quick glance is:
- For list-only models the "is_list" if-statement in the loop in gtk_tree_view_build_tree() will always yield true. We could introduce a variant of the build tree function for "is_list" models, this function then contains a much shorter variant of the loop. There are arguments for such a loop to execute faster on certain architectures, but it is probably too much of a micro-optimization on its own (there are still some function calls, particularly into the RB tree implementation which likely evaporate any benefit).
A more interesting and probably worthwhile case is the following: for list-only models which do not implement reference counting (ref_node and unref_node methods on GtkTreeModel), there is no need to call into the ref_node() function and no need to maintain "iter". The ref_node() call can be eliminated and the do-loop performing a repeated iter_next() call can be replaced with a for-loop that iterates up to the value returned by iter_n_children(). In this tight loop, only RB tree functions are called to insert new nodes into the tree. Having a special gtk_tree_view_build_tree() variant for this case will probably dramatically improve load times for such cases as the GtkTreeModel overhead is greatly reduced.