Setting Up the Menu

The only part of dealing with a context menu that is specific to applets is how to setup the context menu. Once it is setup, this is really just a matter of using GtkAction.

To setup the context menu of the applet, the panel_applet_setup_menu_from_file() function should be used, with a path to a menu XML file and a GtkActionGroup object containing all actions that are used in the menu XML file. The example below shows how to achieve this:

Example 3. Hello World applet, with a context menu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <panel-applet.h>

/* This would usually be defined in config.h */
#define GETTEXT_PACKAGE "hello-world"
/* This would usually be defined in Makefile.am */
#define HELLO_WORLD_UI_DIR "/usr/share/hello-world"

static void hello_world_applet_prefs (GtkAction   *action,
                                      PanelApplet *applet);
static void hello_world_applet_say   (GtkAction   *action,
                                      PanelApplet *applet);

static const GtkActionEntry hello_world_menu_actions [] = {
        { "HelloWorldPrefs", GTK_STOCK_HELP, N_("_Preferences"),
          NULL, NULL,
          G_CALLBACK (hello_world_applet_prefs) },
        { "HelloWorldSay", GTK_STOCK_ABOUT, N_("_Say Hello"),
          NULL, NULL,
          G_CALLBACK (hello_world_applet_say) }
};

static void
hello_world_applet_prefs (GtkAction   *action,
                          PanelApplet *applet)
{
    GtkWidget *dialog;
    dialog = gtk_message_dialog_new (NULL, 0,
                                    GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
                                    "Preferences");
    g_signal_connect (dialog, "response",
                      G_CALLBACK (gtk_widget_destroy), NULL);
    gtk_widget_show (dialog);
}

static void
hello_world_applet_say (GtkAction   *action,
                        PanelApplet *applet)
{
    GtkWidget *dialog;
    dialog = gtk_message_dialog_new (NULL, 0,
                                    GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
                                    "Hello World!");
    g_signal_connect (dialog, "response",
                      G_CALLBACK (gtk_widget_destroy), NULL);
    gtk_widget_show (dialog);
}

static gboolean
hello_world_applet_start (PanelApplet *applet)
{
    GtkWidget *label;
    GtkActionGroup *action_group;
    gchar *ui_path;

    label = gtk_label_new ("Hello World");
    gtk_container_add (GTK_CONTAINER (applet), label);

    action_group = gtk_action_group_new ("Hello World Applet Actions");
    gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
    gtk_action_group_add_actions (action_group,
                                  hello_world_menu_actions,
                                  G_N_ELEMENTS (hello_world_menu_actions),
                                  applet);

    ui_path = g_build_filename (HELLO_WORLD_UI_DIR, "hello-world-menu.xml", NULL);
    panel_applet_setup_menu_from_file (applet, ui_path, action_group);

    g_free (ui_path);
    g_object_unref (action_group);

    gtk_widget_show_all (GTK_WIDGET (applet));

    return TRUE;
}

static gboolean
hello_world_factory_callback (PanelApplet  *applet,
                              const gchar  *iid,
                              gpointer      data)
{
    gboolean retval = FALSE;

    if (g_strcmp0 (iid, "HelloWorldApplet") == 0)
        retval = hello_world_applet_start (applet);

    return retval;
}

PANEL_APPLET_OUT_PROCESS_FACTORY ("HelloWorldFactory",
                                  PANEL_TYPE_APPLET,
                                  hello_world_factory_callback,
                                  NULL)


Here are the changes compared to the simple example with no context menu:

  • We define a list of GtkActionEntry entries: hello_world_menu_actions. This will be used later on to build GtkAction objects, with their label and callback. We obviously implement the callbacks.

  • We change hello_world_applet_start() to define a GtkActionGroup object, to which we add, with gtk_action_group_add_actions(), GtkAction objects based on the GtkActionEntry entries. Note that the the last argument to gtk_action_group_add_actions() will be passed as user data to the callbacks.

  • We also change hello_world_applet_start() to add this GtkActionGroup object to the context menu of the applet, by calling panel_applet_setup_menu_from_file(). This function takes as argument a path to the menu XML file that will define how to display the GtkAction objects in the context menu.