From aa3c12d7c653fbc43a8194bec5807e81f3418f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Fernandes?= Date: Fri, 26 Jan 2024 00:52:59 +0000 Subject: [PATCH] listitemmanager: Really remove section boundary on insert Complete the fix introduced by b05000d8bdbe40771b59edd793574263ef6cb60f It was made to handle the case of inserting at a tracked position which lies immediately after the a section boundary, of this kind: ][ where ']' and '[' are matched FOOTER and HEADER, as in the testsuite. But it doesn't handle the other 2 cases: ]( )[ where ')' is UNMATCHED_FOOTER and '(' is UNMATCHED_HEADER. Indeed, I got testsuite/gtk/listitemmanager to crash on these 2 scenarios. Note: the ')(' case doesn't exist because, at rest, there are no boundary tiles (and no header widget) between untracked sections. So, generalize the previous fix and add comments to make it easier to understand the logic. --- gtk/gtklistitemmanager.c | 65 ++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c index 82c6444cff..f95f754d7b 100644 --- a/gtk/gtklistitemmanager.c +++ b/gtk/gtklistitemmanager.c @@ -963,31 +963,58 @@ gtk_list_item_manager_add_items (GtkListItemManager *self, if (has_sections) { - GtkListTile *section = gtk_list_tile_get_previous_skip (tile); + GtkListTile *header = gtk_list_tile_get_previous_skip (tile); - if (section != NULL && section->type == GTK_LIST_TILE_HEADER) + if (header != NULL && gtk_list_tile_is_header (header)) { - guint start, end; - GtkListTile *footer = gtk_list_tile_get_footer (self, section); - GtkListTile *previous_footer = gtk_list_tile_get_previous_skip (section); + GtkListTile *previous_footer = gtk_list_tile_get_previous_skip (header); - gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), position, &start, &end); - - if (previous_footer != NULL && previous_footer->type == GTK_LIST_TILE_FOOTER && - position > start && position < end) + /* We've inserted right after a header. The new items either don't + * belong in this section or change its length. In either case, we + * need to flag the section header and footer for rematching. + */ + if (header->type == GTK_LIST_TILE_HEADER) { - gtk_list_item_change_clear_header (change, §ion->widget); - gtk_list_tile_set_type (section, GTK_LIST_TILE_REMOVED); - gtk_list_tile_set_type (previous_footer, GTK_LIST_TILE_REMOVED); - - section = gtk_list_tile_get_header (self, previous_footer); + gtk_list_item_change_clear_header (change, &header->widget); + gtk_list_tile_set_type (header, + GTK_LIST_TILE_UNMATCHED_HEADER); + gtk_list_tile_set_type (gtk_list_tile_get_footer (self, header), + GTK_LIST_TILE_UNMATCHED_FOOTER); } - gtk_list_item_change_clear_header (change, §ion->widget); - gtk_list_tile_set_type (section, - GTK_LIST_TILE_UNMATCHED_HEADER); - gtk_list_tile_set_type (footer, - GTK_LIST_TILE_UNMATCHED_FOOTER); + if (previous_footer != NULL && gtk_list_tile_is_footer (previous_footer)) + { + guint start, end; + + gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), + position, &start, &end); + if (position != start) + { + /* At least one item belongs to the previous section, but the + * tile has been inserted after the section boundary. So, this + * boundary must be removed. But first, ensure the previous + * section is flagged for remathing. + */ + if (previous_footer->type == GTK_LIST_TILE_FOOTER) + { + GtkListTile *previous_header = gtk_list_tile_get_header (self, previous_footer); + + gtk_list_item_change_clear_header (change, &previous_header->widget); + gtk_list_tile_set_type (previous_header, + GTK_LIST_TILE_UNMATCHED_HEADER); + } + + /* Now actually remove the boundary before the inserted tile. + */ + gtk_list_tile_set_type (header, GTK_LIST_TILE_REMOVED); + gtk_list_tile_set_type (previous_footer, GTK_LIST_TILE_REMOVED); + + /* We've already ensured the next footer is unmatched, so we + * are done here. gtk_list_item_manager_ensure_items() will + * reintroduce section boundaries where necessary. + */ + } + } } }