Search code examples
cgtkgtktreeview

Change selected row in gtk_tree_selection from C function


I have some efficiency concerns in my application using GTK3 and hope you can provide some help.

I have a gtk_list_store that is shown within a gtk_tree_view. The tree view allows selecting multiple rows. I have connected a callback function to the "changed" event of the tree_selection. This callback is called whenever the user selects or unselects any row. Then some calculations are done and some images and contents of other gtk widgets are updated accordingly. This is fine so far.

I also want to set the selection to the last line of the tree view whenever a new entry is appended to the list store (and some flag is set).

The solution that I found so far is to unselect all lines, select the new line and scroll down the view to the last entry:

// Create new entry
gtk_list_store_append(liststore, &iter);
...
// Set data for entry
gtk_list_store_set(liststore, &iter, ......);
...
// Make the new entry the (only) selected row
gtk_tree_selection_unselect_all(packet_tree_view_selection);
gtk_tree_selection_select_iter(packet_tree_view_selection, &filter_iter);
...
// scroll down to the new entry
GtkTreeModel *model = gtk_tree_model_filter_get_model(packet_store.filtered);
GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
gtk_tree_view_scroll_to_cell(packet_tree_view, path, NULL, FALSE, 1.0, 0.0);

While this basically works fine, I now get two "changed" events for the gtk_tree_view_selection.

As I do calculations and trigger redrawing of some graphics within the on_selection_changed callback I would like to avoid doing the work twice.

Of course I could introduce some global flag to "ignore unselect all" that is checked in the callback function. But this is rather ugly.

Is there some way to change selection in one single call that only triggers one final event after complete change is done? Maybe some locking of events while multiple operations are done and the event is fired when unlocked again?


Solution

  • Whenever you connect a callback to a signal, you get a handler id (a gulong). You can then use g_signal_handler_block and g_signal_handler_unblock to avoid triggering that callback:

    gulong changed_id;
    changed_id = g_signal_connect(packet_tree_view_selection,
                                  "changed",
                                  ...);
    ...
    g_signal_handler_block(packet_tree_view_selection, changed_id);
    gtk_tree_selection_unselect_all(packet_tree_view_selection);
    g_signal_handler_unblock(packet_tree_view_selection, changed_id);
    gtk_tree_selection_select_iter(packet_tree_view_selection, &filter_iter);
    

    If you don't want to keep the handler id around you can also use g_signal_handlers_block_by_func that basically does the same thing by looking up the function in the handlers list of the changed signal.