The Big Picture of GIO's GAction-Family
Big picture of GAction, GActionGroup, GActionMap, GActionEntry, GSimpleAction and GSimpleActionGroup
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
- GIO: How to enable a GMenuItem? GMenu enable / disable
- HowDoI/GAction
- HowDoI/Making an Application Menu
- HowDoI/Using GMenu
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.
- Several
GAction
s can be put into aGActionGroup
. SeveralGActionGroups
can be put into aGActionMap
- 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:
- 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 aGActionEntry
. - Inheritance in black color can be understood as:
GApplication
contains aGActionGroup
GApplication
contains aGActionMap
GSimpleActionGroup
contains aGActionGroup
GSimpleActionGroup
contains aGActionMap
- A
GSimpleActionGroup
can be created and inserted into a GtkWidget (usinggtk_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.
#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