Don't deselect all dives on all selection "change" events

gtk sends the selection change events all the time, for pretty much any
"divelist changed - so selection changed".  The expansion of a trip, the
switch to a new model, yadda yadda.  But we actually want selections to
be sticky across these events, so we can't just forget all of our old
selection state and repopulate it.

So we re-introduce the "am I allowed to change this row" callback, which
we used to use to create a list of every actual selection that was
changed.  But instead of remembering the list (and having the stale
entries issue with that remembered list that caused problems), we now
just use that as a "that *particular* selection cleared" event.

So this callback works as the "which part of the visible, currently
selected state got cleared" notifier, and handles unselection.

Then, when the selection is over, we use the new model of "let's just
traverse the list of things gtk thinks are selected" and use that to
handle new selections in the visible state that gtk actually tracks
well.  So that logic handles the new selections.

This way, dives that aren't visible to gtk don't ever get modified: gtk
won't ask about them being selected or not, and gtk won't track them in
its selection logic, so with this model their state never changes for
us.

gtk selections are annoying.  They are simple for the case gtk knows
about (ie they are *visually* selected in the GUI), but since we very
much want to track selection across events that change the visual state,
we need to have this insane "impedance match".

Reported-by: Dirk Hohdnel <dirk@hohndel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Linus Torvalds 2013-01-30 06:15:23 +11:00 committed by Dirk Hohndel
parent 14524d8e1d
commit 4b5b732f2c

View file

@ -2605,6 +2605,38 @@ static void select_dive(int idx)
}
}
static void deselect_dive(int idx)
{
struct dive *dive = get_dive(idx);
if (dive && dive->selected) {
dive->selected = 0;
amount_selected--;
if (selected_dive > idx)
selected_dive--;
}
}
gboolean modify_selection_cb(GtkTreeSelection *selection, GtkTreeModel *model,
GtkTreePath *path, gboolean was_selected, gpointer userdata)
{
int idx;
timestamp_t when;
GtkTreeIter iter;
if (!was_selected)
return TRUE;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1);
if (idx < 0) {
dive_trip_t *trip = find_trip_by_time(when);
if (trip)
trip->selected = 0;
} else {
deselect_dive(idx);
}
return TRUE;
}
/* This gets called for each selected entry after a selection has changed */
static void entry_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
{
@ -2636,13 +2668,6 @@ static void entry_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *
/* 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
@ -2740,6 +2765,8 @@ 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);