Working with Actions

I created a menu with the help of GMenu and added it to my application with:

gtk_application_set_menubar ( application, G_MENU_MODEL ( main_menu ) );

Next thing, I created for this Menu 3 different Entries:

static const GActionEntry first_accell[] =
{
    { "one",  one_call,   NULL, NULL, NULL, { 0, 0, 0 } },
    { "two",  two_call,   NULL, NULL, NULL, { 0, 0, 0 } },
    { "tree", tree_call,  NULL, NULL, NULL, { 0, 0, 0 } },
};

static const GActionEntry second_accell[] =
{
    { "file", file_call,      NULL, NULL, NULL, { 0, 0, 0 } }
};


static const GActionEntry third_accell[] =
{
    { "first",  first_call,    NULL, NULL, NULL, { 0, 0, 0 } },
    { "secont", second_call,   NULL, NULL, NULL, { 0, 0, 0 } },
    { "third",  third_call,   NULL, NULL, NULL, { 0, 0, 0 } },
};

and added to my application with:

g_action_map_add_action_entries ( G_ACTION_MAP ( application ), first_accell,  G_N_ELEMENTS ( first_accell ),  application );
g_action_map_add_action_entries ( G_ACTION_MAP ( application ), second_accell, G_N_ELEMENTS ( second_accell ), NULL );
g_action_map_add_action_entries ( G_ACTION_MAP ( application ), third_accell,  G_N_ELEMENTS ( third_accell ),  NULL );

Everything works Fine.

Now I was thinking to create some groups instead of adding them all in that manner and I came to this:

GSimpleActionGroup *first_group = g_simple_action_group_new ();
g_action_map_add_action_entries ( G_ACTION_MAP ( first_group ), first_accell, G_N_ELEMENTS ( first_accell ), application );

Now what I would Like to know is. how to add/join this group to the application to make them work?

GApplication implements GActionMap. If you’re using it (you should), you could avoid to create a GSimpleActionGroup, and just use your GApplication/GtkApplication instead (with the app. prefix).

Edit: oh, and GtkApplicationWindow also does, by the way (with the win. prefix).

You are saying that I can not do what I was asking?

No, I’m just trying to make your code smaller by taking shortcuts. :smiley: You can use gtk_widget_insert_action_group() to add the action group to a specific widget. But it’s quite usual to use the two pre-defined “groups,” that are the one of the application (app.) and the one of the window (win.).

I do not have a Widget, I am using GMenu, GMenuModel and GMenuItem and this are not Widgets if I am not Wrong.

If you have a menubar, you probably have a GtkWindow, that is a GtkWidget. :wink:

This is what I have so far:
Screenshot from 2020-07-15 18-02-19

#include <gtk/gtk.h>

void one_call    ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void two_call    ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void tree_call   ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void first_call  ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void second_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void third_call  ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void file_call   ( GSimpleAction *action, GVariant *parameter, gpointer user_data );

static void startup ( GtkApplication *app )
{
    GSimpleActionGroup *first_group;
    GSimpleActionGroup *second_group;
    GSimpleActionGroup *third_group;
    ///GActionMap  *action_map;

    static const GActionEntry first_accell[] =
    {
        { "one",  one_call,   NULL, NULL, NULL, { 0, 0, 0 } },
        { "two",  two_call,   NULL, NULL, NULL, { 0, 0, 0 } },
        { "tree", tree_call,  NULL, NULL, NULL, { 0, 0, 0 } },
    };

    static const GActionEntry second_accell[] =
    {
        { "file", file_call,      NULL, NULL, NULL, { 0, 0, 0 } }
    };


    static const GActionEntry third_accell[] =
    {
        { "first",  first_call,    NULL, NULL, NULL, { 0, 0, 0 } },
        { "secont", second_call,   NULL, NULL, NULL, { 0, 0, 0 } },
        { "third",  third_call,   NULL, NULL, NULL, { 0, 0, 0 } },
    };



    /*
    action_map   = G_ACTION_MAP ( app );
    g_action_map_add_action_entries ( action_map, first_accell,  G_N_ELEMENTS ( first_accell ),  NULL );
    g_action_map_add_action_entries ( action_map, second_accell, G_N_ELEMENTS ( second_accell ), NULL );
    g_action_map_add_action_entries ( action_map, third_accell,  G_N_ELEMENTS ( third_accell ),  NULL );
    */


    first_group  = g_simple_action_group_new ();
    second_group = g_simple_action_group_new ();
    third_group  = g_simple_action_group_new ();

    g_action_map_add_action_entries ( G_ACTION_MAP( first_group ),  first_accell,  G_N_ELEMENTS ( first_accell ),  app );
    g_action_map_add_action_entries ( G_ACTION_MAP( second_group ), second_accell, G_N_ELEMENTS ( second_accell ), NULL );
    g_action_map_add_action_entries ( G_ACTION_MAP( third_group ),  third_accell,  G_N_ELEMENTS ( third_accell ),  NULL );
}


static void activate ( GtkApplication *app )
{
    GtkWidget *window;
    GMenu     *menu;
    GMenu     *first_menu;
    GMenuItem *item;

    window = gtk_application_window_new ( app );
    gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );

    gtk_window_set_application ( GTK_WINDOW ( window ), GTK_APPLICATION ( app ) );
    gtk_window_set_title ( GTK_WINDOW ( window ), "Example" );

    menu       = g_menu_new ();
    first_menu = g_menu_new ();

    g_menu_insert_submenu ( menu, 0, "First", G_MENU_MODEL ( first_menu ) );


    item = g_menu_item_new ( "One", "app.one" );
    g_menu_insert_item ( first_menu, 0, G_MENU_ITEM ( item ) );
    g_object_unref ( item );

    item = g_menu_item_new ( "Two", "app.two" );
    g_menu_insert_item ( first_menu, 1, G_MENU_ITEM ( item ) );
    g_object_unref ( item );

    item = g_menu_item_new ( "Tree", "app.tree" );
    g_menu_insert_item ( first_menu, 2, G_MENU_ITEM ( item ) );
    g_object_unref ( item );

    gtk_application_set_menubar ( app, G_MENU_MODEL ( menu ) );

    gtk_widget_show_all ( GTK_WIDGET ( window ) );
    g_object_unref ( menu );
}

int main ( void )
{
    GtkApplication *app;
    int status;

    app = gtk_application_new  ( "org.gtk.example", G_APPLICATION_FLAGS_NONE );
    g_signal_connect_swapped   ( app, "startup",  G_CALLBACK ( startup ),  app );
    g_signal_connect_swapped   ( app, "activate", G_CALLBACK ( activate ), app );
    status = g_application_run ( G_APPLICATION ( app ), 0, NULL );
    g_object_unref ( app );

    return status;
}

void one_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked One call\n" );
}

void two_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked TWO call\n" );
}

void tree_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Open file\n" );
}

void first_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Undo\n" );
}

void second_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Cut\n" );
}

void third_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Copy\n" );
}

void file_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Save file\n" );
}

There’s a Python example on how to build a menu bar with GMenu available in an older topic. It should be trivially portable to C.

I do not know python, just started my First year school .

I’d strongly encourage you to not do this in C, either. Learning Python is probably a better idea, for a newcomer.

Well I need it for a project on my school :expressionless:

The only interest of using an ActionGroup is to… group actions, so not having one per action would be a good idea. :wink: But your commented code (regarding action_map = G_ACTION_MAP (app)) looks good to me, even if I’m not fluent in C; is it failing somewhere?

Well, thank you for not helping me and for pointing me to another direction.
I will have to check the Documentation.

That was an attempt to help you

Various people have made suggestions and comments on how to use action groups

You where directed towards an example, admittedly in Python not C, that you can work from

At this point I’m not sure
A) What you are trying to achieve
B) What problem your facing

Remember actions and menu items are independent, you do not have to use different action groups for different menus

We’re not here to help you pass your schoolwork, I’m afraid to say.

Where exactly did I asked about helping me to fix/make my Homework?
Did I not provide my work and did I not said, that I have a working assignment which actually works?

If I was asking for a Question, it was because I needed some information and I was definitely not expecting someone to fix my code.

Now to be honest I am not sure for what are you standing here for. I thought that I had a fair Question and a fair Answer to this Question was expected as well.

If I ask something in Italian Language, I do not want to know how one in Spanish would spell or say it just because they are similar and both are Latin.

I just asked, if there are 3 groups created and need them to insert them into my Application (not widget) how do I do that. If me is the problem because I use it wrong, then you are those who will tell me that It can not be done or it is a wrong approach, isn’t it?

I even provided a strait example code which illustrate the situation, but I got nothing which helps me (or at least something which I understand. I simply do not speak Python).
This means that either I can not do it in C or you are not willing to point me to that direction.

This Is what I have at this point:

#include <gtk/gtk.h>

void one_call    ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void two_call    ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void tree_call   ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void first_call  ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void second_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void third_call  ( GSimpleAction *action, GVariant *parameter, gpointer user_data );
void file_call   ( GSimpleAction *action, GVariant *parameter, gpointer user_data );

static void startup ( GtkApplication *app )
{
    GSimpleActionGroup *first_group;
    GSimpleActionGroup *second_group;
    GSimpleActionGroup *third_group;

    static const GActionEntry first_accell[] =
    {
        { "one",  one_call,   NULL, NULL, NULL, { 0, 0, 0 } },
        { "two",  two_call,   NULL, NULL, NULL, { 0, 0, 0 } },
        { "tree", tree_call,  NULL, NULL, NULL, { 0, 0, 0 } },
    };

    static const GActionEntry second_accell[] =
    {
        { "file", file_call,      NULL, NULL, NULL, { 0, 0, 0 } }
    };


    static const GActionEntry third_accell[] =
    {
        { "first",  first_call,    NULL, NULL, NULL, { 0, 0, 0 } },
        { "secont", second_call,   NULL, NULL, NULL, { 0, 0, 0 } },
        { "third",  third_call,   NULL, NULL, NULL, { 0, 0, 0 } },
    };

    first_group  = g_simple_action_group_new ();
    second_group = g_simple_action_group_new ();
    third_group  = g_simple_action_group_new ();

    g_action_map_add_action_entries ( G_ACTION_MAP( first_group ),  first_accell,  G_N_ELEMENTS ( first_accell ),  app );
    g_action_map_add_action_entries ( G_ACTION_MAP( second_group ), second_accell, G_N_ELEMENTS ( second_accell ), NULL );
    g_action_map_add_action_entries ( G_ACTION_MAP( third_group ),  third_accell,  G_N_ELEMENTS ( third_accell ),  NULL );
}


static void activate ( GtkApplication *app )
{
    GtkWidget *window;
    GMenu     *menu;
    GMenu     *first_menu;
    GMenuItem *item;

    window = gtk_application_window_new ( app );
    gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );

    gtk_window_set_application ( GTK_WINDOW ( window ), GTK_APPLICATION ( app ) );
    gtk_window_set_title ( GTK_WINDOW ( window ), "Example" );

    menu       = g_menu_new ();
    first_menu = g_menu_new ();

    g_menu_insert_submenu ( menu, 0, "First", G_MENU_MODEL ( first_menu ) );


    item = g_menu_item_new ( "One", "app.one" );
    g_menu_insert_item ( first_menu, 0, G_MENU_ITEM ( item ) );
    g_object_unref ( item );

    item = g_menu_item_new ( "Two", "app.two" );
    g_menu_insert_item ( first_menu, 1, G_MENU_ITEM ( item ) );
    g_object_unref ( item );

    item = g_menu_item_new ( "Tree", "app.tree" );
    g_menu_insert_item ( first_menu, 2, G_MENU_ITEM ( item ) );
    g_object_unref ( item );

    gtk_application_set_menubar ( app, G_MENU_MODEL ( menu ) );

    gtk_widget_show_all ( GTK_WIDGET ( window ) );
    g_object_unref ( menu );
}

int main ( void )
{
    GtkApplication *app;
    int status;

    app = gtk_application_new  ( "org.gtk.example", G_APPLICATION_FLAGS_NONE );
    g_signal_connect_swapped   ( app, "startup",  G_CALLBACK ( startup ),  app );
    g_signal_connect_swapped   ( app, "activate", G_CALLBACK ( activate ), app );
    status = g_application_run ( G_APPLICATION ( app ), 0, NULL );
    g_object_unref ( app );

    return status;
}

void one_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked One call\n" );
}

void two_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked TWO call\n" );
}

void tree_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Open file\n" );
}

void first_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Undo\n" );
}

void second_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Cut\n" );
}

void third_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Copy\n" );
}

void file_call ( GSimpleAction *action, GVariant *parameter, gpointer user_data )
{
    ( void ) action;
    ( void ) parameter;
    ( void ) user_data;
    g_print ( "You clicked Save file\n" );
}

I’m not sure what your saying here but I think your getting at the fact a Python example was provided

Really this Italian & Spanish analogy doesn’t work, things are very similar in C & Python for using gtk.

For example in C we do

gtk_widget_set_tooltip_text (widget, "text");

But in python that’s

widget.set_tooltip_text ("text")

Whilst clearly they are not exactly the same they are plenty close enough to be helpful

You possibly do, we’re just not sure what it is :slight_smile:

a G[tk]Application is a GActionGroup, you cannot add other GActionGroups to it

However anything that extends GtkWidget, such as GtkWindow, has an insert_action_group method that allows you to add additional groups

But for your menubar actions you may as well add them directly to your GtkApplication or GtkApplicaionWindow - there is no benefit to splitting into extra groups (indeed that just complicates things)

You’d be surprised, nobody is expecting you to understand to intricacies of bytes vs strings or module resolution. If your familiar with C (which it seems you are) you can understand enough python to learn from it.

[code block]

I see your setting the menubar in activate, you probably want to move that to startup

1 Like

I needed to check, but you’re right, the documentation is clear here.

So, to be complete, there’s one difference I know (well, I think I know :smiley:): the win. prefix is exported over D-Bus more or less automatically, possibly opening an unexpected way to interact with the application. I usually use both win. and a custom ui. prefixes.

Thank you all.
I got my Answer:

 a G[tk]Application  *is*  a GActionGroup, you cannot add other GActionGroups to it

For future reference, it says this right near the tops of the docs:

Implemented Interfaces

GApplication implements GActionGroup and GActionMap.

So is app.