[PATCH] Rewrite gtk dive selection tracking logic

Linus Torvalds torvalds at linux-foundation.org
Mon Jan 28 22:29:17 PST 2013


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Mon, 28 Jan 2013 22:22:31 -0800
Subject: [PATCH] Rewrite gtk dive selection tracking logic

We used to generate a list of possibly changed selections using the gtk
tree selection "selection function".

But that's actually meant to just tell gtk whether an entry can be
selected or not, and our list of possibly changed entries ended up being
stale if the selection change was due to a list entry removal, for
example.

So rip out the old model entirely, and instead just walk the whole
selection that gtk gives us on a selection "change" event.  We throw all
our old selections away when this happens, and just rebuild it all.

This should fix the occasional internal gtklib-quartz assertion that
Henrik is seeing.  And it actually simplifies the code too.

Reported-by: Henrik Brautaset Aronsen <subsurface at henrik.synth.no>
Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

This hopefully fixes the problem Henrik saw. Henrik, mind testing?

It also simplifies the logic a lot, as can be seen by the fact that it 
removes twice as many lines as it adds. Much more straightforward code.

 divelist.c | 170 ++++++++++++++++++++-----------------------------------------
 1 file changed, 56 insertions(+), 114 deletions(-)

diff --git a/divelist.c b/divelist.c
index 82ef339d8152..b31c9ac25133 100644
--- a/divelist.c
+++ b/divelist.c
@@ -217,118 +217,6 @@ void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *pa
 		gtk_tree_selection_select_iter(selection, iter);
 }
 
-static GList *selection_changed = NULL;
-
-/*
- * This is called _before_ the selection is changed, for every single entry;
- *
- * We simply create a list of all changed entries, and make sure that the
- * group entries go at the end of the list.
- */
-gboolean modify_selection_cb(GtkTreeSelection *selection, GtkTreeModel *model,
-			GtkTreePath *path, gboolean was_selected, gpointer userdata)
-{
-	GtkTreeIter iter, *p;
-
-	if (!gtk_tree_model_get_iter(model, &iter, path))
-		return TRUE;
-
-	/* Add the group entries to the end */
-	p = gtk_tree_iter_copy(&iter);
-	if (gtk_tree_model_iter_has_child(model, p))
-		selection_changed = g_list_append(selection_changed, p);
-	else
-		selection_changed = g_list_prepend(selection_changed, p);
-	return TRUE;
-}
-
-static void select_dive(struct dive *dive, int selected)
-{
-	if (dive->selected != selected) {
-		amount_selected += selected ? 1 : -1;
-		dive->selected = selected;
-	}
-}
-
-/*
- * This gets called when a dive group has changed selection.
- */
-static void select_dive_group(GtkTreeModel *model, GtkTreeSelection *selection, GtkTreeIter *iter, int selected)
-{
-	int first = 1;
-	GtkTreeIter child;
-
-	if (selected == selected_children(model, iter))
-		return;
-
-	if (!gtk_tree_model_iter_children(model, &child, iter))
-		return;
-
-	do {
-		int idx;
-		struct dive *dive;
-
-		gtk_tree_model_get(model, &child, DIVE_INDEX, &idx, -1);
-		if (first && selected)
-			selected_dive = idx;
-		first = 0;
-		dive = get_dive(idx);
-		if (dive->selected == selected)
-			continue;
-
-		select_dive(dive, selected);
-		if (selected)
-			gtk_tree_selection_select_iter(selection, &child);
-		else
-			gtk_tree_selection_unselect_iter(selection, &child);
-	} while (gtk_tree_model_iter_next(model, &child));
-}
-
-/*
- * This gets called _after_ the selections have changed, for each entry that
- * may have changed. Check if the gtk selection state matches our internal
- * selection state to verify.
- *
- * The group entries are at the end, this guarantees that we have handled
- * all the dives before we handle groups.
- */
-static void check_selection_cb(GtkTreeIter *iter, GtkTreeSelection *selection)
-{
-	GtkTreeModel *model = MODEL(dive_list);
-	struct dive *dive;
-	int idx, gtk_selected;
-
-	gtk_tree_model_get(model, iter,
-		DIVE_INDEX, &idx,
-		-1);
-	dive = get_dive(idx);
-	gtk_selected = gtk_tree_selection_iter_is_selected(selection, iter);
-	if (idx < 0)
-		select_dive_group(model, selection, iter, gtk_selected);
-	else {
-		select_dive(dive, gtk_selected);
-		if (gtk_selected)
-			selected_dive = idx;
-	}
-	gtk_tree_iter_free(iter);
-}
-
-/* this is called when gtk thinks that the selection has changed */
-static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model)
-{
-	GList *changed = selection_changed;
-
-	selection_changed = NULL;
-	g_list_foreach(changed, (GFunc) check_selection_cb, selection);
-	g_list_free(changed);
-#if DEBUG_SELECTION_TRACKING
-	dump_selection();
-#endif
-
-	process_selected_dives();
-	repaint_dive();
-}
-
 const char *star_strings[] = {
 	ZERO_STARS,
 	ONE_STARS,
@@ -2707,6 +2595,62 @@ static void sort_column_change_cb(GtkTreeSortable *treeview, gpointer data)
 	}
 }
 
+static void select_dive(struct dive *dive)
+{
+	if (dive && !dive->selected) {
+		dive->selected = 1;
+		amount_selected++;
+	}
+}
+
+/* This gets called for each selected entry after a selection has changed */
+static void entry_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+	int idx;
+	timestamp_t when;
+
+	gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1);
+	if (idx < 0) {
+		int i;
+		struct dive *dive;
+		dive_trip_t *trip = find_trip_by_time(when);
+
+		if (!trip)
+			return;
+		trip->selected = 1;
+		/* If this is expanded, let the gtk selection happen for each dive under it */
+		if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), path))
+			return;
+		/* Otherwise, consider each dive under it selected */
+		for_each_dive(i, dive) {
+			if (dive->divetrip == trip)
+				select_dive(dive);
+		}
+	} else {
+		select_dive(get_dive(idx));
+	}
+}
+
+/* this is called when gtk thinks that the selection has changed */
+static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model)
+{
+	int i;
+	struct dive *dive;
+
+	amount_selected = 0;
+	for_each_dive(i, dive)
+		dive->selected = 0;
+
+	gtk_tree_selection_selected_foreach(selection, entry_selected, model);
+
+#if DEBUG_SELECTION_TRACKING
+	dump_selection();
+#endif
+
+	process_selected_dives();
+	repaint_dive();
+}
+
 GtkWidget *dive_list_create(void)
 {
 	GtkTreeSelection  *selection;
@@ -2794,8 +2738,6 @@ GtkWidget *dive_list_create(void)
 	g_signal_connect(dive_list.listmodel, "sort-column-changed", G_CALLBACK(sort_column_change_cb), NULL);
 	g_signal_connect(dive_list.treemodel, "sort-column-changed", G_CALLBACK(sort_column_change_cb), NULL);
 
-	gtk_tree_selection_set_select_function(selection, modify_selection_cb, NULL, NULL);
-
 	dive_list.container_widget = gtk_scrolled_window_new(NULL, NULL);
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dive_list.container_widget),
 			       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-- 
1.8.1.2.422.g08c0e7f



More information about the subsurface mailing list