Search code examples
gtk4

How to programmatically add a check mark to a GMenuItem (gtk4 using c)


Only GMenu, GMenuItem, GMenuModel, and GSimpleAction can be used to create menus in GTK4. Is it possible to put a check mark next to a known GMenuItem?

I've menaged to enable/disable menu item by manipulating GSimpleAction. However, there is no documentation how to put check mark.


Solution

  • I also tried to find out about this and I figured it out.

    The type of a menu item depends on the type of action it was mapped to, you cannot control the menu item type directly. For a normal action created with g_simple_action_new it will appear as just text, but if the action was created like so:

    gboolean initial_value = 1;
    GVariant* variant = g_variant_new_boolean(initial_state);
    g_action = g_simple_action_new_stateful("stateful", NULL, variant);
    

    We're on our way to have a checkmark menu item.

    We then need to add this action to our application using g_action_map_add_action, connect to the activate signal of the action with g_signal_connect, then add a menu item to our menu model model like so:

    GMenuItem* item = g_menu_item_new("item label", "app.stateful");
    g_menu_append_item(G_MENU(model), item);
    g_object_unref(item);
    

    Where item label is the label and stateful was the name of the stateful action we created.

    After all these steps (remember to connect to the signal and keep the action enabled or it will appear greyed out) the item will magically appear with a checkmark.

    To change the current state of the item, we change the state of the action:

    // get state
    gboolean current_state = g_variant_get_boolean(g_action_get_state(G_ACTION(g_action))));
    
    // set state
    gboolean new_state = current_state;
    g_action_change_state(G_ACTION(g_action), g_variant_new_boolean(new_state));
    

    I tested it and it appears that the formatting of the menu item depends on this argument when creating the action:

    // create as checkmark
    g_action = g_simple_action_new_stateful("stateful", NULL, variant);
    
    // create as dot
    g_action = g_simple_action_new_stateful("stateful", G_VARIANT_TYPE_BOOLEAN, variant);
    

    Why? I have no idea, you'd think setting it to boolean would make it a checkmark but no, setting it to NULL does. How is anyone supposed to figure this out? I also have no idea, I spend half a day reverse engineering but maybe there's a doc page on it somewhere.

    I love GTK4, it runs so well now and the menus are really flexible and powerful since they can contain widgets directly now, but the menu and action-related docs are truly awful, the information is there but scattered everywhere between the Gio, GLib and GTK doc pages and simple questions like "why is this item greyed out" can take hours to answer.