From c3ce4ef8c56f7d85e9adc9f63c8dbccf3d7b44a5 Mon Sep 17 00:00:00 2001 From: Soeren Sandmann Date: Wed, 9 Nov 2005 05:39:25 +0000 Subject: [PATCH] Add new tree_view_foreach_visible() function. Wed Nov 9 00:24:11 2005 Soeren Sandmann * treeviewutils.[ch]: Add new tree_view_foreach_visible() function. * sysprof.c: Add update_screenshot_window() function. --- ChangeLog | 7 ++ TODO | 6 ++ sysprof.c | 258 ++++++++++++++++++++++++++++++------------------ treeviewutils.c | 80 +++++++++++---- treeviewutils.h | 8 ++ 5 files changed, 244 insertions(+), 115 deletions(-) diff --git a/ChangeLog b/ChangeLog index 985b3c76..d79bdadd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Nov 9 00:24:11 2005 Soeren Sandmann + + * treeviewutils.[ch]: Add new tree_view_foreach_visible() + function. + + * sysprof.c: Add update_screenshot_window() function. + Mon Nov 7 23:42:26 2005 Soeren Sandmann * sysprof.c: Add beginning of a screenshot diff --git a/TODO b/TODO index 661867a4..89187d2d 100644 --- a/TODO +++ b/TODO @@ -184,6 +184,12 @@ Before 1.2: UI: "generate screenshot" menu item pops up a window with a text area + a radio buttons "text/html". When you flick them, the text area is automatically updated. + - beginning in CVS: + - why does the window not remember its position when + you close it with the close button, but does remember + it when you use the wm button or the menu item? It actually + seems that it only forgets the position when you click the + button with the mouse. But not if you use the keyboard ... - Find out how gdb does backtraces; they may have a better way. Also find out what dwarf2 is and how to use it. Look into libunwind. diff --git a/sysprof.c b/sysprof.c index 27e57de6..623c4934 100644 --- a/sysprof.c +++ b/sysprof.c @@ -69,7 +69,7 @@ struct Application GtkWidget * screenshot_item; GtkWidget * samples_label; - + gboolean screenshot_window_visible; GtkWidget * screenshot_textview; GtkWidget * screenshot_close_button; @@ -80,7 +80,7 @@ struct Application ProfileCaller * callers; int timeout_id; - + char * loaded_profile; gboolean profile_from_file; /* FIXME - not10: This is a kludge. Figure out how @@ -106,7 +106,7 @@ show_samples_timeout (gpointer data) Application *app = data; char *label; int n_samples; - + switch (app->state) { case INITIAL: @@ -120,14 +120,14 @@ show_samples_timeout (gpointer data) case DISPLAYING: n_samples = profile_get_size (app->profile); break; - + default: g_assert_not_reached(); break; } label = g_strdup_printf ("Samples: %d", n_samples); - + gtk_label_set_label (GTK_LABEL (app->samples_label), label); g_free (label); @@ -155,9 +155,9 @@ update_sensitivity (Application *app) gboolean sensitive_reset_button; GtkWidget *active_radio_button; - + gboolean has_samples; - + switch (app->state) { case INITIAL: @@ -172,7 +172,7 @@ update_sensitivity (Application *app) case PROFILING: has_samples = (collector_get_n_samples (app->collector) > 0); - + sensitive_profile_button = has_samples; sensitive_save_as_button = has_samples; sensitive_reset_button = has_samples; @@ -191,15 +191,15 @@ update_sensitivity (Application *app) sensitive_samples_label = FALSE; active_radio_button = app->profile_button; break; - + default: g_assert_not_reached(); break; } - + gtk_toggle_tool_button_set_active ( GTK_TOGGLE_TOOL_BUTTON (active_radio_button), TRUE); - + /* "profile" widgets */ gtk_widget_set_sensitive (GTK_WIDGET (app->profile_button), sensitive_profile_button); @@ -211,7 +211,7 @@ update_sensitivity (Application *app) sensitive_save_as_button); gtk_widget_set_sensitive (app->save_as_item, sensitive_save_as_button); - + /* "start" widgets */ gtk_widget_set_sensitive (GTK_WIDGET (app->start_button), sensitive_start_button); @@ -232,14 +232,14 @@ update_sensitivity (Application *app) gtk_widget_set_sensitive (GTK_WIDGET (app->callers_view), sensitive_tree_views); gtk_widget_set_sensitive (GTK_WIDGET (app->descendants_view), sensitive_tree_views); gtk_widget_set_sensitive (GTK_WIDGET (app->samples_label), sensitive_samples_label); - + if (app->screenshot_window_visible) gtk_widget_show (app->screenshot_window); else gtk_widget_hide (app->screenshot_window); - - gtk_check_menu_item_set_active ( - GTK_CHECK_MENU_ITEM (app->screenshot_item), app->screenshot_window_visible); + + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (app->screenshot_item), + app->screenshot_window_visible); queue_show_samples (app); } @@ -254,12 +254,12 @@ set_busy (GtkWidget *widget, cursor = gdk_cursor_new (GDK_WATCH); else cursor = NULL; - + gdk_window_set_cursor (widget->window, cursor); if (cursor) gdk_cursor_unref (cursor); - + gdk_flush (); } @@ -275,7 +275,7 @@ set_application_title (Application *app, if (app->loaded_profile) g_free (app->loaded_profile); - + app->loaded_profile = new_name; if (app->loaded_profile) @@ -302,7 +302,7 @@ delete_data (Application *app) gtk_tree_view_set_model (GTK_TREE_VIEW (app->callers_view), NULL); gtk_tree_view_set_model (GTK_TREE_VIEW (app->descendants_view), NULL); } - + collector_reset (app->collector); queue_show_samples (app); @@ -340,7 +340,7 @@ static void on_menu_item_activated (GtkWidget *menu_item, GtkWidget *tool_button) { GtkToggleToolButton *button = GTK_TOGGLE_TOOL_BUTTON (tool_button); - + if (!gtk_toggle_tool_button_get_active (button)) gtk_toggle_tool_button_set_active (button, TRUE); } @@ -355,11 +355,11 @@ on_start_toggled (GtkWidget *widget, gpointer data) { return; } - + if (collector_start (app->collector, NULL)) { delete_data (app); - + app->state = PROFILING; } else @@ -373,7 +373,7 @@ on_start_toggled (GtkWidget *widget, gpointer data) "\n" "as root."); } - + update_sensitivity (app); } @@ -448,7 +448,7 @@ fill_main_list (Application *app) ProfileObject *object = list->data; GtkTreeIter iter; double profile_size = profile_get_size (profile); - + gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, @@ -652,7 +652,7 @@ ensure_profile (Application *app) return; app->profile = collector_create_profile (app->collector); - + collector_stop (app->collector); fill_lists (app); @@ -667,7 +667,7 @@ on_about_activated (GtkWidget *widget, gpointer data) { #define OSLASH "\303\270" Application *app = data; - + gtk_show_about_dialog (GTK_WINDOW (app->main_window), "logo", app->icon, "name", APPLICATION_NAME, @@ -680,7 +680,7 @@ static void on_profile_toggled (GtkWidget *widget, gpointer data) { Application *app = data; - + if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (app->profile_button))) { set_busy (app->main_window, TRUE); @@ -699,7 +699,7 @@ static void on_reset_clicked (gpointer widget, gpointer data) { Application *app = data; - + set_busy (app->main_window, TRUE); delete_data (app); @@ -711,7 +711,7 @@ on_reset_clicked (gpointer widget, gpointer data) } update_sensitivity (app); - + set_busy (app->main_window, FALSE); } @@ -781,7 +781,7 @@ on_save_as_clicked (gpointer widget, set_busy (app->main_window, FALSE); - retry: +retry: if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { GError *err = NULL; @@ -801,7 +801,7 @@ on_save_as_clicked (gpointer widget, { sorry (app->main_window, "Could not save %s: %s", filename, err->message); - + set_busy (dialog, FALSE); g_free (filename); goto retry; @@ -825,14 +825,14 @@ set_loaded_profile (Application *app, set_busy (app->main_window, TRUE); delete_data (app); - + app->state = DISPLAYING; app->profile = profile; app->profile_from_file = TRUE; fill_lists (app); - + set_application_title (app, name); update_sensitivity (app); @@ -852,7 +852,7 @@ show_could_not_open (Application *app, filename, err->message); } - + static void on_open_clicked (gpointer widget, gpointer data) @@ -861,7 +861,7 @@ on_open_clicked (gpointer widget, gchar *filename = NULL; Profile *profile = NULL; GtkWidget *dialog; - + set_busy (app->main_window, TRUE); dialog = gtk_file_chooser_dialog_new ("Open", @@ -872,24 +872,24 @@ on_open_clicked (gpointer widget, NULL); gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); - + set_busy (app->main_window, FALSE); - retry: +retry: if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { GError *err = NULL; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); - + set_busy (dialog, TRUE); - + profile = profile_load (filename, &err); if (!profile) { set_busy (dialog, FALSE); - + show_could_not_open (app, filename, err); g_error_free (err); g_free (filename); @@ -900,14 +900,14 @@ on_open_clicked (gpointer widget, set_busy (dialog, FALSE); } - + gtk_widget_destroy (dialog); - + if (profile) { g_assert (filename); set_loaded_profile (app, filename, profile); - + g_free (filename); } } @@ -935,13 +935,13 @@ expand_descendants_tree (Application *app) double top_value = 0.0; GtkTreePath *first_path; GList *list; - + first_path = gtk_tree_path_new_first(); - + all_paths = g_list_prepend (all_paths, first_path); - + n_rows = 1; - + gtk_tree_model_get_iter (model, &iter, first_path); gtk_tree_model_get (model, &iter, OBJECT_TOTAL, &top_value, @@ -954,10 +954,10 @@ expand_descendants_tree (Application *app) double best_value; int n_children; int i; - + best_value = 0.0; best_path = NULL; - + for (list = all_paths; list != NULL; list = list->next) { GtkTreePath *path = list->data; @@ -974,13 +974,13 @@ expand_descendants_tree (Application *app) { best_value = value; best_path = path; - + gtk_tree_model_get_iter (model, &best_iter, path); } } - + gtk_tree_model_get_iter (model, &iter, best_path); - + n_children = gtk_tree_model_iter_n_children (model, &best_iter); if (n_children && (best_value / top_value) > 0.04 && @@ -988,50 +988,110 @@ expand_descendants_tree (Application *app) { gtk_tree_view_expand_row (GTK_TREE_VIEW (app->descendants_view), best_path, FALSE); n_rows += n_children; - + if (gtk_tree_path_get_depth (best_path) < 4) { GtkTreePath *path = gtk_tree_path_copy (best_path); gtk_tree_path_down (path); - + for (i = 0; i < n_children; ++i) { all_paths = g_list_prepend (all_paths, path); - + path = gtk_tree_path_copy (path); gtk_tree_path_next (path); } - + gtk_tree_path_free (path); } } - + all_paths = g_list_remove (all_paths, best_path); + + if (!all_paths && n_rows == 1) + { + /* Always expand at least once */ + gtk_tree_view_expand_row (GTK_TREE_VIEW (app->descendants_view), + best_path, FALSE); + } + gtk_tree_path_free (best_path); } - + for (list = all_paths; list != NULL; list = list->next) gtk_tree_path_free (list->data); g_list_free (all_paths); } +typedef struct +{ + int text_width; + int self_width; + int cumulative_width; +} Widths; + static void -on_object_selection_changed (GtkTreeSelection *selection, - gpointer data) +compute_widths (GtkTreeView *view, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + GtkTreeModel *model = gtk_tree_view_get_model (view); +} + +static void +add_text (GtkTreeView *view, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) { Application *app = data; +} +static void +update_screenshot_window (Application *app) +{ + typedef gboolean (* GtkTreeModelForeachFunc) (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data); + + /* FIXME: clear the text buffer here */ + + if (app->descendants) + { + Widths widths; + + widths.text_width = 0; + widths.self_width = 0; + widths.cumulative_width = 0; + + tree_view_foreach_visible (app->descendants_view, + compute_widths, + &widths); + + tree_view_foreach_visible (app->descendants_view, + add_text, + app); + } +} + +static void +on_object_selection_changed (GtkTreeSelection *selection, + gpointer data) +{ + Application *app = data; + set_busy (app->main_window, TRUE); - + gdk_window_process_all_updates (); /* Display updated selection */ fill_descendants_tree (app); fill_callers_list (app); - + if (get_current_object (app)) expand_descendants_tree (app); + update_screenshot_window (app); + set_busy (app->main_window, FALSE); } @@ -1116,7 +1176,7 @@ on_callers_row_activated (GtkTreeView *tree_view, Application *app = data; goto_object (app, tree_view, path, CALLERS_OBJECT); - + gtk_widget_grab_focus (GTK_WIDGET (app->callers_view)); } @@ -1125,7 +1185,7 @@ on_screenshot_activated (GtkCheckMenuItem *menu_item, Application *app) { app->screenshot_window_visible = gtk_check_menu_item_get_active (menu_item); - + update_sensitivity (app); } @@ -1135,7 +1195,7 @@ on_screenshot_window_delete (GtkWidget *window, Application *app) { app->screenshot_window_visible = FALSE; - + update_sensitivity (app); } @@ -1144,12 +1204,13 @@ on_screenshot_close_button_clicked (GtkWidget *widget, Application *app) { app->screenshot_window_visible = FALSE; - + update_sensitivity (app); } static void set_sizes (GtkWindow *window, + GtkWindow *screenshot_window, GtkWidget *hpaned, GtkWidget *vpaned) { @@ -1171,6 +1232,12 @@ set_sizes (GtkWindow *window, gtk_paned_set_position (GTK_PANED (vpaned), height / 2); gtk_paned_set_position (GTK_PANED (hpaned), width / 2); + + width = monitor.width * 5 / 8; + height = monitor.height * 5/ 8; + + gtk_window_resize (screenshot_window, width, height); + } static void @@ -1198,9 +1265,9 @@ build_gui (Application *app) GladeXML *xml; GtkTreeSelection *selection; GtkTreeViewColumn *col; - + set_shadows (); - + if (!g_file_test (GLADE_FILE, G_FILE_TEST_EXISTS) || !g_file_test (ICON_FILE, G_FILE_TEST_EXISTS)) { @@ -1208,26 +1275,23 @@ build_gui (Application *app) "Sysprof was not compiled or installed correctly.\n" "\n" "Running \"make install\" may solve this problem.\n"); - + return FALSE; } - + xml = glade_xml_new (GLADE_FILE, NULL, NULL); /* Main Window */ app->main_window = glade_xml_get_widget (xml, "main_window"); app->icon = gdk_pixbuf_new_from_file (ICON_FILE, NULL); - + gtk_window_set_icon (GTK_WINDOW (app->main_window), app->icon); g_signal_connect (G_OBJECT (app->main_window), "delete_event", G_CALLBACK (on_delete), NULL); gtk_widget_realize (GTK_WIDGET (app->main_window)); - set_sizes (GTK_WINDOW (app->main_window), - glade_xml_get_widget (xml, "hpaned"), - glade_xml_get_widget (xml, "vpaned")); /* Tool items */ @@ -1251,7 +1315,7 @@ build_gui (Application *app) g_signal_connect (G_OBJECT (app->save_as_button), "clicked", G_CALLBACK (on_save_as_clicked), app); - + app->samples_label = glade_xml_get_widget (xml, "samples_label"); @@ -1276,19 +1340,19 @@ build_gui (Application *app) g_signal_connect (G_OBJECT (app->reset_item), "activate", G_CALLBACK (on_reset_clicked), app); - + g_signal_connect (G_OBJECT (app->open_item), "activate", G_CALLBACK (on_open_clicked), app); g_signal_connect (G_OBJECT (app->save_as_item), "activate", G_CALLBACK (on_save_as_clicked), app); - + g_signal_connect (G_OBJECT (app->screenshot_item), "activate", G_CALLBACK (on_screenshot_activated), app); - + g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "quit")), "activate", G_CALLBACK (on_delete), NULL); - + g_signal_connect (G_OBJECT (glade_xml_get_widget (xml, "about")), "activate", G_CALLBACK (on_about_activated), app); @@ -1323,27 +1387,33 @@ build_gui (Application *app) g_signal_connect (app->descendants_view, "row-activated", G_CALLBACK (on_descendants_row_activated), app); gtk_tree_view_column_set_expand (col, TRUE); - + gtk_widget_grab_focus (GTK_WIDGET (app->object_view)); - - /* Screenshot window */ + + /* screenshot window */ app->screenshot_window = glade_xml_get_widget (xml, "screenshot_window"); app->screenshot_textview = glade_xml_get_widget (xml, "screenshot_textview"); app->screenshot_close_button = glade_xml_get_widget (xml, "screenshot_close_button"); - + g_signal_connect (app->screenshot_window, "delete_event", G_CALLBACK (on_screenshot_window_delete), app); - + g_signal_connect (app->screenshot_close_button, "clicked", G_CALLBACK (on_screenshot_close_button_clicked), app); + /* set sizes */ + set_sizes (GTK_WINDOW (app->main_window), + GTK_WINDOW (app->screenshot_window), + glade_xml_get_widget (xml, "hpaned"), + glade_xml_get_widget (xml, "vpaned")); + /* hide/show widgets */ gtk_widget_show_all (app->main_window); gtk_widget_hide (app->dummy_button); gtk_widget_hide (app->screenshot_window); queue_show_samples (app); - + return TRUE; } @@ -1351,7 +1421,7 @@ static void on_new_sample (gpointer data) { Application *app = data; - + if (app->state == PROFILING) update_sensitivity (app); } @@ -1360,7 +1430,7 @@ static Application * application_new (void) { Application *app = g_new0 (Application, 1); - + app->collector = collector_new (on_new_sample, app); app->state = INITIAL; @@ -1381,7 +1451,7 @@ load_file (gpointer data) Application *app = file_open_data->app; GError *err = NULL; Profile *profile; - + set_busy (app->main_window, TRUE); profile = profile_load (filename, &err); @@ -1397,7 +1467,7 @@ load_file (gpointer data) show_could_not_open (app, filename, err); g_error_free (err); } - + g_free (file_open_data); return FALSE; @@ -1412,21 +1482,21 @@ main (int argc, gtk_init (&argc, &argv); app = application_new (); - + if (!build_gui (app)) return -1; update_sensitivity (app); - + if (argc > 1) { FileOpenData *file_open_data = g_new0 (FileOpenData, 1); file_open_data->filename = argv[1]; file_open_data->app = app; - + g_idle_add (load_file, file_open_data); } - + gtk_main (); return 0; diff --git a/treeviewutils.c b/treeviewutils.c index 2472eb61..8f8f2c8f 100644 --- a/treeviewutils.c +++ b/treeviewutils.c @@ -39,11 +39,11 @@ tree_view_unset_sort_ids (GtkTreeView *tree_view) { GList *columns = gtk_tree_view_get_columns (tree_view); GList *l; - + for (l = columns; l; l = l->next) { gtk_tree_view_column_set_sort_column_id (l->data, -1); } - + g_list_free (columns); } @@ -52,12 +52,12 @@ tree_view_set_sort_ids (GtkTreeView *tree_view) { GList *columns = gtk_tree_view_get_columns (tree_view); GList *l; - + for (l = columns; l; l = l->next) { int column_id = GPOINTER_TO_INT (g_object_get_data (l->data, "mi-saved-sort-column")); gtk_tree_view_column_set_sort_column_id (l->data, column_id); } - + g_list_free (columns); } @@ -72,9 +72,9 @@ list_iter_get_index (GtkTreeModel *model, g_assert (gtk_tree_path_get_depth (path) == 1); result = gtk_tree_path_get_indices (path)[0]; gtk_tree_path_free (path); - + return result; - + } GtkTreeViewColumn * @@ -82,7 +82,7 @@ add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; - + renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); column = gtk_tree_view_column_new_with_attributes (title, renderer, @@ -91,7 +91,7 @@ add_plain_text_column (GtkTreeView *view, const gchar *title, gint model_column) gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_append_column (view, column); column_set_sort_id (column, model_column); - + return column; } @@ -103,7 +103,7 @@ pointer_to_text (GtkTreeViewColumn *tree_column, gpointer p; gchar *text; int column = GPOINTER_TO_INT (data); - + gtk_tree_model_get (tree_model, iter, column, &p, -1); text = g_strdup_printf ("%p", p); g_object_set (cell, "text", text, NULL); @@ -123,11 +123,11 @@ double_to_text (GtkTreeViewColumn *tree_column, gdouble d; gchar *text; ColumnInfo *info = data; - + gtk_tree_model_get (tree_model, iter, info->column, &d, -1); - + text = g_strdup_printf (info->format, d); - + g_object_set (cell, "text", text, NULL); g_free (text); } @@ -146,21 +146,21 @@ add_double_format_column (GtkTreeView *view, const gchar *title, gint model_colu GtkCellRenderer *renderer; GtkTreeViewColumn *column; ColumnInfo *column_info = g_new (ColumnInfo, 1); - + renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "xalign", 1.0, NULL); - + column = gtk_tree_view_column_new (); gtk_tree_view_column_set_title (column, title); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_resizable (column, FALSE); - + column_info->column = model_column; column_info->format = g_strdup (format); gtk_tree_view_column_set_cell_data_func (column, renderer, double_to_text, column_info, free_column_info); - + gtk_tree_view_append_column (view, column); column_set_sort_id (column, model_column); @@ -172,9 +172,9 @@ add_pointer_column (GtkTreeView *view, const gchar *title, gint model_column) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; - + renderer = gtk_cell_renderer_text_new (); - + column = gtk_tree_view_column_new (); if (title) gtk_tree_view_column_set_title (column, title); @@ -182,7 +182,7 @@ add_pointer_column (GtkTreeView *view, const gchar *title, gint model_column) gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_cell_data_func (column, renderer, pointer_to_text, GINT_TO_POINTER (model_column), NULL); - + gtk_tree_view_append_column (view, column); column_set_sort_id (column, model_column); @@ -202,7 +202,7 @@ save_sort_state (GtkTreeView *view) { SortState *state = NULL; GtkTreeModel *model = gtk_tree_view_get_model (view); - + if (model && GTK_IS_TREE_SORTABLE (model)) { state = g_new (SortState, 1); state->is_sorted = gtk_tree_sortable_get_sort_column_id ( @@ -218,7 +218,7 @@ restore_sort_state (GtkTreeView *view, gpointer st) { SortState *state = st; GtkTreeModel *model = gtk_tree_view_get_model (view); - + if (state) { if (state->is_sorted && model && GTK_IS_TREE_SORTABLE (model)) { gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), @@ -230,3 +230,41 @@ restore_sort_state (GtkTreeView *view, gpointer st) gtk_tree_sortable_sort_column_changed (GTK_TREE_SORTABLE (model)); } + + +static void +process_iter (GtkTreeView *view, + GtkTreeIter *iter, + VisibleCallback callback, + gpointer data) +{ + GtkTreeModel *model = gtk_tree_view_get_model (view); + GtkTreePath *path; + GtkTreeIter child; + + path = gtk_tree_model_get_path (model, iter); + + callback (view, path, iter, data); + + if (gtk_tree_view_row_expanded (view, path)) { + if (gtk_tree_model_iter_children (model, &child, iter)) { + do { + process_iter (view, &child, callback, data); + } while (gtk_tree_model_iter_next (model, &child)); + } + } + + gtk_tree_path_free (path); +} + +void +tree_view_foreach_visible (GtkTreeView *view, + VisibleCallback callback, + gpointer data) +{ + GtkTreeModel *model = gtk_tree_view_get_model (view); + GtkTreeIter iter; + + if (gtk_tree_model_get_iter_first (model, &iter)) + process_iter (view, &iter, callback, data); +} diff --git a/treeviewutils.h b/treeviewutils.h index 908a22c0..9b9c5dcb 100644 --- a/treeviewutils.h +++ b/treeviewutils.h @@ -43,3 +43,11 @@ GtkTreeViewColumn *add_pointer_column (GtkTreeView *view, gpointer save_sort_state (GtkTreeView *view); void restore_sort_state (GtkTreeView *view, gpointer state); + +typedef void (* VisibleCallback) (GtkTreeView *view, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data); +void tree_view_foreach_visible (GtkTreeView *view, + VisibleCallback callback, + gpointer data);