GNOME Bugzilla – Bug 328833
GtkTreeModelSort cause serious crash, and it's totally unusable.
Last modified: 2006-02-08 14:26:53 UTC
I'm developing a new file manager called PCMan File Manager with gtk+ 2.8.10. http://pcmanfm.sourceforge.net/ This is a high-speed and lightweight file manager compared with most of other file managers. It can be started ``within one second'', and is ``much more faster'' than GtkFileChooser when loading directories with thousands of files. (This is not the point.) I use all GtkTreeModel related classes to develop my application. Finally, I found GtkTreeModelSort is unusable. I use a GtkListStore to store my data, and wrap it with GtkTreeModelSort to do sorting, and wrap GtkTreeModelSort with a GtkTreeModelFilter to exclude some hidden files from display. When I delete ``more than one'' rows at the same time in its child model (GtkListStore), the change is ``NOT'' synchronized in its parent model (GtkModelSort). Hence the toplevel GtkTreeModelFilter ``doesn't know'' there are some rows deleted. This is unfortunate because the GtkTreeView will ``NOT'' update its display when some rows int underlying GtkListStore has been deleted. Moreover, some GtkTreePaths in toplevel GtkTreeModelFilter will be invalid after their counterparts in underlying GtkListStore are deleted. The wost case is, when I call gtk_tree_model_get_iter in toplevel GtkTreeModelFilter with an ``INVALID'' path (the real row it refers has been deleted in underlying GtkListStore), the API still returns TRUE to indicate it gets a ``VALID'' GtkTreeIter for me. And then, when I call gtk_tree_model_get on this `INVALID` GtkTreeIter, all I get are access violation and segmentation faults. These serious problems make GtkTreeModelSort and my project totally ``UNUSABLE''. And when I hack into the source code of GtkTreeModelSort (gtktreemodelsort.c), I got these following comments: /* WARNING: this code is dangerous, can cause sleepless nights, * can cause your dog to die among other bad things * * we warned you and we're not liable for any head injuries. */ /* FIXME: I still have doubts if this works */ static void gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model, GtkTreePath *s_path, gpointer data) I insist this kind of warnings ``SHOULD'' be put in gtk+ API docs. I used lots of these things then finally found my project is totally broken bacause of unknown bugs of GTK+. This is very very frustrating. Neither hacking GtkTreeModelSort to make it work nor rewritting my app with Qt are good idea for me. My project is almost finished, but now totally blocked by GTK+. Please help me!! This will be a great file manager if these problems can be solved. Test case: I think my project itself is the best test case. It use GtkTreeView, GtkTreeModel, GtkTreeModelFilter, GtkTreeModelSort, GtkTreePathReference, ...etc. Almost all GtkTreeView related things are used. Each of these classes seems to work fine, but unfortunately, after all these are comboined, I got a broken app. You can got my source code at SourceForge anonymous CVS. http://sourceforge.net/cvs/?group_id=156956 BTW, the mothod I used in this project can solve the performance problem with GtkFileChooserDialog. So, it's worth hacking. ;-)
The code causing problems in my app is in "src/foldercontent.c" static void folder_content_delete_file( FolderContent* content, const char* filename ); static gboolean on_fam_event(GIOChannel *channel, GIOCondition cond, gpointer user_data ); When monitored files on disk are deleted (notified by FAM), I have to update the GtkTreeView. So I install a idle handler with g_idle_add. Then the handler which will update all folder views is called. static gboolean call_update_callback( gpointer data ); The update_callback then calls gboolean update_folder_view_visible_region( FileBrowserData* data ) in src/filebrowser.c Then, the app crashes because GtkTreeView returns some invalid GtkTreeIters. (Cause by the preceding problems I described) In my app, gtk_tree_view_get_visible_range sometimes returns invalid paths, too. I believe that they are cause by the same problems, the underlying GtkTreeModelSort. Please help me. After these problems are solved, my app will be a good file manager and one of the best demonstration of the power of GtkTreeView/GtkTreeModel.
There is no need at all to wrap a list store in a GtkTreeModelSort, since the liststore is sortable itself.
(In reply to comment #2) > There is no need at all to wrap a list store in a GtkTreeModelSort, > since the liststore is sortable itself. > There ``IS'' need if you have ``large set of data''. Without GtkTreeModelSort, you cannot share the same model between different views, if the view items are displayed in different order. Sort the GtkListStore itself will affect ``ALL'' view diaplaying it. Using different GtkListStore for different views is a bad idea when the list is very large. This not only greatly increase memory usage, but also greatly increase the view creation time (Since each view have to create its own list store, and cannot share existing models). This will induce great performance hit if the large list is created form on-disk files or database since the I/O operations are dramatically increased. Cache the list myself in memory is not a good idea because I have to keep an additional list to hold all data beside those inside GtkListStores. If the model is changed in one view, developers will have to synchronize the changes by themselves between all these duplicated lists. And this is really a very bad idea. That's why we need GtkTreeModelSort. According to GTK+ API doc: The primary purpose of this model is to provide a way to sort a different model without modifying it. This is very important. Using GtkTreeSortable interface has nothing to do with wrapping a GtkListStore with a GtkTreeModelSort. They are totally different thing and serve different needs.
After tracing, I found the problem. In gtk_tree_model_sort_row_deleted, there is several lines: if ( level->ref_count == 0 ) { /* This will prune the level, so I can just emit the signal and * not worry about cleaning this level up. * Careful, root level is not cleaned up in increment stamp. */ ptk_tree_model_sort_increment_stamp ( tree_model_sort ); gtk_tree_path_free ( path ); if ( level == tree_model_sort->root ) { ptk_tree_model_sort_free_level ( tree_model_sort, tree_model_sort->root ); tree_model_sort->root = NULL; } return ; } I found level->ref_count seems to be always 0, and this cause the problem. After any row is deleted, ``level'' always gets freed. Hence when aother row in the same level are deleted, there is no ``level'', and then ptk_real_tree_model_sort_convert_child_path_to_path cannot convert s_path to path since there is no information about current level. (level and its internal array has been freed and this shouldn't happen) So that's why when several rows are deleted at the same time, only the first deleted row can correctly emit "row-deleted" signal to its parent. If you guys can get level->ref_count correctly counted, the bug can be fixed.
I have encountered exact the same thing mentioned above. Where the patch supplied by HJ Yee works perfect for me.
oops, just realized that it wasn't a patch but just the correction in comment #4.
Compiled pcmanfm (cvs versions HEAD, Jan 28, Jan 25 and Jan 23) against gtk+ HEAD and the problems did not occur. I assume the problems have been solved by the GtkTreeModelFilter rewrite and GtkTreeModelSort bugfixes in HEAD, if this appears not to be the case later on, please reopen the bug.