Adding a popover menu as child widget takes a lot of time in some situations
GTK 4.0.3 or 4.1.1
Here is the code to reproduce the issue, which I tried to reduce as much as possible:
#include <gtk/gtk.h>
#define N_SUBMENUS 5
#define N_ITEMS 3
static const GActionEntry entries[] =
{
{ "action", NULL, NULL, NULL, NULL }
};
static GMenuModel *
create_menubar_model (void)
{
GMenu *menubar, *menu_0, *menu_1, *section, *submenu;
GMenuItem *item;
gchar *label;
gint n, m;
menubar = g_menu_new ();
menu_0 = g_menu_new ();
item = g_menu_item_new_submenu ("level 0", G_MENU_MODEL (menu_0));
g_menu_append_item (menubar, item);
g_object_unref (item);
menu_1 = g_menu_new ();
item = g_menu_item_new_submenu ("level 1", G_MENU_MODEL (menu_1));
g_menu_append_item (menu_0, item);
g_object_unref (item);
section = g_menu_new ();
item = g_menu_item_new_section ("section", G_MENU_MODEL (section));
g_menu_append_item (menu_1, item);
g_object_unref (item);
for (n = 0; n < N_SUBMENUS; n++)
{
label = g_strdup_printf ("%d", n + 1);
submenu = g_menu_new ();
item = g_menu_item_new_submenu (label, G_MENU_MODEL (submenu));
g_menu_append_item (section, item);
g_object_unref (item);
g_free (label);
for (m = 0; m < N_ITEMS; m++)
{
label = g_strdup_printf ("%d%d", n + 1, m + 1);
item = g_menu_item_new (label, "grp.action");
g_menu_append_item (submenu, item);
g_object_unref (item);
g_free (label);
}
}
return G_MENU_MODEL (menubar);
}
gint main (gint argc, gchar **argv)
{
GtkWidget *window, *menubar;
GMenuModel *model;
GActionGroup *group;
GMainLoop *loop;
gtk_init ();
model = create_menubar_model ();
menubar = gtk_popover_menu_bar_new_from_model (model);
g_object_unref (model);
window = gtk_window_new ();
group = G_ACTION_GROUP (g_simple_action_group_new ());
g_action_map_add_action_entries (G_ACTION_MAP (group), entries, G_N_ELEMENTS (entries), NULL);
gtk_widget_insert_action_group (window, "grp", group);
g_printerr ("%s: start timer\n", G_STRLOC);
g_test_timer_start ();
gtk_window_set_child (GTK_WINDOW (window), menubar);
g_printerr ("%s: stop timer: %f\n", G_STRLOC, g_test_timer_elapsed ());
gtk_widget_show (window);
loop = g_main_loop_new (NULL, FALSE);
g_signal_connect_swapped (window, "destroy", G_CALLBACK (g_main_loop_quit), loop);
g_main_loop_run (loop);
g_main_loop_unref (loop);
}
The instruction gtk_window_set_child (GTK_WINDOW (window), menubar);
takes a few seconds to execute on my small laptop, you can adjust N_SUBMENUS
and N_ITEMS
if they are not high enough in your case.
The key points are as follows:
- This level of nesting is necessary for the problem to appear
- The use of a section including the list of final sub-menus is necessary (a sub-menu does not make the problem appear)
- A valid action name is necessary for the problem to appear
For the sake of clarity and simplicity, I used a menubar, but the problem is the same if you use gtk_popover_menu_new_from_model()
to create a context menu attached to a widget (although the execution times are then lower).