Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

The Big Picture of GIO's GAction-Family

5.00/5 (2 votes)
12 May 2020CPOL1 min read 5.3K  
Big picture of GAction, GActionGroup, GActionMap, GActionEntry, GSimpleAction and GSimpleActionGroup
This post is meant for new developers to GIO/GTK who want to get an idea of how things are connected. You will learn about the interaction between the interfaces, look at the big picture and also see example code.

Putting in Picture GIO's GAction*

This tip tries to put up a picture of the following:

  • GAction
  • GActionGroup
  • GActionMap
  • GActionEntry
  • GSimpleAction
  • GSimpleActionGroup

Who Is This For?

New developers to GIO/GTK, who just stumbled across the GAction-family and want to get a "bigger picture" of how things are connected.

Links to Related Information

Essence Regarding Usage

You probably don't need GAction or GSimpleAction. Using them is tedious and more difficult.

Interaction Between Interfaces

GAction, GActionGroup and GActionMap are interfaces. The following image shows how the interfaces work together.

Image 1

  • Several GActions can be put into a GActionGroup. Several GActionGroups can be put into a GActionMap
  • Actions have names
  • Groups have names
  • Action maps gather all actions with their full name

The Big Picture

The following image shows which interfaces are implemented by which classes:

Image 2

  • The greyed out GAction part is what you probably don't need. Using it (especially in C) is unintuitive and very tedious (keyword: casting).
  • Instead of a GAction, you use a GActionEntry.
  • Inheritance in black color can be understood as:
    • GApplication contains a GActionGroup
    • GApplication contains a GActionMap
    • GSimpleActionGroup contains a GActionGroup
    • GSimpleActionGroup contains a GActionMap
  • A GSimpleActionGroup can be created and inserted into a GtkWidget (using gtk_widget_insert_action_group). That way, you can add specific actions to widgets. That way, you can set a new (, local) shortcut (accelerator) for that widget.

Example Code

The following is a fully functional C example code creating a GMenu and attaching GActions to it.

C++
#include <gtk/gtk.h>
#include <stdio.h>

//------------------------------------------------------------

GMenuModel * createMenu(){

  GMenu * menu = g_menu_new();
  {  
    // app prefix is needed, because the regarding actions 
    // are registered at the "app".
    g_menu_append(menu, "Item1", "app.item1_action1");    
    g_menu_append(menu, "Item2", "app.item2_action1");    

    GMenu * submenu = g_menu_new();
    {      
      g_menu_append(submenu, "Subitem1", "subaction1");
      g_menu_append_submenu(menu,"Submenu1",(GMenuModel*)submenu);
    }    
  }
  return (GMenuModel*)menu;
}

//------------------------------------------------------------

void exampleAction (GSimpleAction *action,
                    GVariant      *parameter,
                    gpointer       user_data)
{
  printf("hello world\n");
}

//------------------------------------------------------------
/**
* @brief: Do basic window setup and start real population of the window.
*         `activate` gets called, when the app is 
*         called without any file arguments
*/
static void
activate (GApplication *app,
          gpointer      user_data)
{
  GtkWindow *window = (GtkWindow*)gtk_application_window_new (GTK_APPLICATION (app));
  gtk_window_set_default_size (window, 200, 200);
  gtk_window_set_position     (window, GTK_WIN_POS_CENTER);


  GMenuModel * menu = createMenu();

  gtk_application_set_app_menu(GTK_APPLICATION(app), (GMenuModel*)menu);
  g_object_unref (menu);

  // Register an action to your app:
  {
    // The following blocks show two different ways

    // Using GActionEntry (Recommended because it is simple)
    GActionEntry actions[] = {
      {"item1_action1", exampleAction, NULL, NULL, NULL}
    };
    g_action_map_add_action_entries(G_ACTION_MAP(app),actions, 1, NULL);  


    // Using GAction / GSimpleAction (Not recommended, it is because tedious)
    GAction * action = (GAction*)g_simple_action_new("item2_action1",NULL);
    g_signal_connect(action, "activate", G_CALLBACK(exampleAction), NULL);
    g_action_map_add_action(G_ACTION_MAP(app), action);
  }

  // Note: Registering action to the application puts them automatically 
  //       inside the GActionGroup calle "app.". That is the reason why
  //       the GMenuItems above have to add "app." as a prefix


  gtk_widget_show_all ((GtkWidget*)window);
}
// ------------------------------------------------------------
int 
main (int argc, char *argv[]) 
{
  // always use a GtkApplication. Otherwise, advanced features might 
  // "magically" not work for you.
  GtkApplication * app = gtk_application_new(NULL,G_APPLICATION_FLAGS_NONE);
  g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);

  int status = g_application_run(G_APPLICATION (app), argc, argv);
  g_object_unref(app);

  return status;
}

History

  • 2nd May, 2020: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)