gtk_popover_menu_bar_add_child: works only for the top level of the menu bar
Behavior confirms on
- Debian 12 + GTK 4.8.3
- Fedora 36 + GTK 4.6.9
- Ubuntu 22.04 LTS + GTK 4.6.6
Current behavior
When using the gtk_popover_menu_bar_add_child()
to insert a widget in a menu bar,
the function only search for menu item with the proper custom attribute in the first level of the menu bar.
I noticed that gtk_popover_menu_add_child()
was called by gtk_popover_menu_bar_add_child()
as many times
as the number of menu items in the top level of the menu bar, I think this should be done recursively for
all levels of the menu bar.
Expected outcome
To be able to use custom attribute, and insert widget, on any levels of the menu bar.
My understanding is that the gtk_popover_menu_bar_add_child()
is not needed, but instead should be replaced by a recursive call to the gtk_popover_menu_add_child()
function.
Sample code that illustrates the issue:
#include <gtk/gtk.h>
GtkApplication * TestApp = NULL;
void menu_bar_action (GSimpleAction * action, GVariant * parameter, gpointer data)
{
gchar * name = g_strdup_printf ("%s", g_action_get_name(G_ACTION(action)));
if (g_strcmp0 (name, "quit") == 0)
{
g_application_quit (G_APPLICATION(TestApp));
}
}
GMenuItem * create_gmenu_item (const gchar * label, const gchar * action, const gchar * custom)
{
GMenuItem * item;
item = g_menu_item_new (label, action);
g_menu_item_set_attribute (item, "use-markup", "s", "TRUE", NULL);
// Setting custom here:
if (custom)
{
g_menu_item_set_attribute (item, "custom", "s", custom, NULL);
/* Checking custom value: */
GVariant * cust = g_menu_item_get_attribute_value (item, "custom", g_variant_type_new("s"));
if (cust) g_print ("item is:: %s, custom is:: %s\n", label, g_variant_get_string (cust, NULL));
}
return item;
}
void append_menu_item (GMenu * menu, const gchar * label, const gchar * action, const gchar * custom)
{
GMenuItem * item = create_gmenu_item (label, action, custom);
g_menu_append_item (menu, item);
g_object_unref (item);
}
GMenu * second_level_menu ()
{
GMenu * menu = g_menu_new ();
append_menu_item (menu, "Level 2: C(H)<sub>2</sub>", "None", "CH2-2");
append_menu_item (menu, "Level 2: C(H)<sub>3</sub>", "None", NULL);
append_menu_item (menu, "Level 2: C(H)<sub>4</sub>", "None", NULL);
return menu;
}
void run_program (GApplication * app, gpointer data)
{
GtkWidget * window = gtk_application_window_new (GTK_APPLICATION(app));
gtk_window_set_title (GTK_WINDOW(window), "Test");
gtk_window_set_resizable (GTK_WINDOW(window), TRUE);
gtk_widget_set_size_request (window, 900, 450);
GMenu * menubar = g_menu_new ();
GMenu * menu = g_menu_new ();
// Trying different things just in case:
append_menu_item (menu, "C(H)<sub>2</sub>", "None", "CH2");
append_menu_item (menu, "C(H)<sub>3</sub>", "None", NULL);
append_menu_item (menu, "C(H)<sub>4</sub>", "None", NULL);
g_menu_append_submenu (menu, "Second level", (GMenuModel*)second_level_menu());
append_menu_item (menu, "Quit", "app.quit", NULL);
g_menu_append_submenu (menubar, "First level", G_MENU_MODEL (menu));
g_object_unref (menu);
GtkWidget * menu_bar = gtk_popover_menu_bar_new_from_model (G_MENU_MODEL(menubar));
// Adding a widget at custom 'CH2', this is working
gtk_popover_menu_bar_add_child ((GtkPopoverMenuBar *)menu_bar, gtk_label_new("Level 1: Custom CH2"), "CH2");
// Adding a widget at custom 'CH2-2' second level, this is not working
gtk_popover_menu_bar_add_child ((GtkPopoverMenuBar *)menu_bar, gtk_label_new("Level 2: Custom CH2"), "CH2-2");
GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child ((GtkWindow *)window, vbox);
GtkWidget * hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_append (GTK_BOX(vbox), hbox);
gtk_box_append (GTK_BOX(hbox), menu_bar);
gtk_widget_show (menu_bar);
GSimpleAction * act = g_simple_action_new ("quit", NULL);
g_signal_connect (act, "activate", G_CALLBACK(menu_bar_action), NULL);
g_action_map_add_action (G_ACTION_MAP(GTK_APPLICATION(app)), G_ACTION(act));
//gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW(window), TRUE);
gtk_window_present (GTK_WINDOW(window));
}
int main (int argc, char *argv[])
{
// setlocale(LC_ALL,"en_US");
gtk_disable_setlocale ();
#if GLIB_MINOR_VERSION < 74
TestApp = gtk_application_new (g_strdup_printf ("test._%d.gtk", (int)clock()), G_APPLICATION_FLAGS_NONE);
#else
TestApp = gtk_application_new (g_strdup_printf ("test._%d.gtk", (int)clock()), G_APPLICATION_DEFAULT_FLAGS);
#endif
g_signal_connect (G_OBJECT(TestApp), "activate", G_CALLBACK(run_program), NULL);
int status = g_application_run (G_APPLICATION (TestApp), 0, NULL);
g_object_unref (TestApp);
return status;
}
Edited by Sébastien Le Roux