--- a/ui/gtk/list.c Fri Sep 11 19:26:51 2026 +0200 +++ b/ui/gtk/list.c Sat Sep 12 10:06:47 2026 +0200 @@ -3154,27 +3154,40 @@ } } +static void listbox2_toggle_node(UiListBox2Row *rowdata) { + rowdata->expanded = !rowdata->expanded; + if(rowdata->expanded) { + IMAGE_SET_ICON(rowdata->expander, "pan-down-symbolic"); + } else { + IMAGE_SET_ICON(rowdata->expander, "pan-end-symbolic"); + } + listbox2_node_children_update_visibility(rowdata, rowdata->expanded); +} + #if GTK_CHECK_VERSION(4, 0, 0) -void listbox2_node_expand( +static void listbox2_node_expand( GtkGestureClick *self, gint n_press, gdouble x, gdouble y, UiListBox2Row *rowdata) { - rowdata->expanded = !rowdata->expanded; - if(rowdata->expanded) { - gtk_image_set_from_icon_name(GTK_IMAGE(rowdata->expander), "pan-down-symbolic"); - } else { - gtk_image_set_from_icon_name(GTK_IMAGE(rowdata->expander), "pan-end-symbolic"); - } - listbox2_node_children_update_visibility(rowdata, rowdata->expanded); + listbox2_toggle_node(rowdata); } #endif #if GTK_MAJOR_VERSION == 3 +static gboolean listbox2_node_expand( + GtkWidget *widget, + GdkEventButton *event, + UiListBox2Row *rowdata) +{ + listbox2_toggle_node(rowdata); + return TRUE; +} + #endif #define LISTBOX2_ITEM_HBOX_SPACING 10 @@ -3182,7 +3195,9 @@ GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, LISTBOX2_ITEM_HBOX_SPACING); rowdata->expanded = 1; - GtkWidget *expander = gtk_image_new_from_icon_name("pan-down-symbolic"); + GtkWidget *expander = gtk_image_new(); + GtkWidget *expander0 = expander; + IMAGE_SET_ICON(expander, "pan-down-symbolic"); int exp_width = 0; #if GTK_CHECK_VERSION(4, 0, 0) gtk_widget_measure(expander, @@ -3199,6 +3214,16 @@ #else int exp_height; gtk_widget_get_preferred_width(expander, &exp_width, &exp_height); + + expander0 = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(expander0), expander); + + gtk_widget_set_events(expander, GDK_BUTTON_PRESS_MASK); + g_signal_connect( + expander0, + "button-release-event", + G_CALLBACK(listbox2_node_expand), + rowdata); #endif gtk_widget_set_margin_start(hbox, identation * (exp_width+LISTBOX2_ITEM_HBOX_SPACING)); @@ -3206,7 +3231,7 @@ gtk_widget_set_visible(expander, FALSE); // normal items have the expander icon in the front if(!item->is_header) { - BOX_ADD(hbox, expander); + BOX_ADD(hbox, expander0); } rowdata->expander = expander; @@ -3239,7 +3264,7 @@ // headings have the expander at the end if(item->is_header) { - BOX_ADD(hbox, expander); + BOX_ADD(hbox, expander0); WIDGET_ADD_CSS_CLASS(label, "ui-listbox-header-row"); rowdata->heading = TRUE; } @@ -3248,9 +3273,16 @@ g_object_set_data(G_OBJECT(row), "ui-listbox-row-data", rowdata); } +static void listbox2_remove_all(UiListBox2 *listbox) { + CxIterator i = cxListIterator(listbox->rows); + cx_foreach(UiListBox2Row *, row, i) { + LISTBOX_REMOVE(listbox->listbox, row->row); + } + cxListClear(listbox->rows); +} + static void listbox2_update_all(UiListBox2 *listbox) { - gtk_list_box_remove_all(listbox->listbox); - cxListClear(listbox->rows); + listbox2_remove_all(listbox); if(!listbox->var) { return; } @@ -3284,7 +3316,7 @@ g_signal_connect(row, "leave-notify-event", G_CALLBACK(listbox_row_leave), NULL); #endif - gtk_list_box_append(listbox->listbox, row); + gtk_list_box_insert(listbox->listbox, row, -1); UiListBox2Row row_data = {0}; row_data.listbox = listbox; row_data.row = row;