add GActionMap interface
[platform/upstream/glib.git] / gio / gactionmap.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; either version 2 of the licence or (at
7  * your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General
15  * Public License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Authors: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gsimpleaction.h"
25 #include "gactiongroup.h"
26 #include "gactionmap.h"
27 #include "gaction.h"
28
29 G_DEFINE_INTERFACE (GActionMap, g_action_map, G_TYPE_ACTION_GROUP)
30
31 static void
32 g_action_map_default_init (GActionMapInterface *iface)
33 {
34 }
35
36 GAction *
37 g_action_map_lookup_action (GActionMap  *action_map,
38                             const gchar *action_name)
39 {
40   return G_ACTION_MAP_GET_IFACE (action_map)
41     ->lookup_action (action_map, action_name);
42 }
43
44 void
45 g_action_map_add_action (GActionMap  *action_map,
46                          GAction     *action)
47 {
48   return G_ACTION_MAP_GET_IFACE (action_map)
49     ->add_action (action_map, action);
50 }
51
52 void
53 g_action_map_remove_action (GActionMap  *action_map,
54                             const gchar *action_name)
55 {
56   return G_ACTION_MAP_GET_IFACE (action_map)
57     ->remove_action (action_map, action_name);
58 }
59
60 /**
61  * GActionEntry:
62  * @name: the name of the action
63  * @activate: the callback to connect to the "activate" signal of the
64  *            action
65  * @parameter_type: the type of the parameter that must be passed to the
66  *                  activate function for this action, given as a single
67  *                  GVariant type string (or %NULL for no parameter)
68  * @state: the initial state for this action, given in GVariant text
69  *         format.  The state is parsed with no extra type information,
70  *         so type tags must be added to the string if they are
71  *         necessary.
72  * @change_state: the callback to connect to the "change-state" signal
73  *                of the action
74  *
75  * This struct defines a single action.  It is for use with
76  * g_action_map_add_action_entries().
77  *
78  * The order of the items in the structure are intended to reflect
79  * frequency of use.  It is permissible to use an incomplete initialiser
80  * in order to leave some of the later values as %NULL.  All values
81  * after @name are optional.  Additional optional fields may be added in
82  * the future.
83  *
84  * See g_action_map_add_action_entries() for an example.
85  **/
86
87 /**
88  * g_action_map_add_action_entries:
89  * @simple: a #GSimpleActionGroup
90  * @entries: a pointer to the first item in an array of #GActionEntry
91  *           structs
92  * @n_entries: the length of @entries, or -1
93  * @user_data: the user data for signal connections
94  *
95  * A convenience function for creating multiple #GSimpleAction instances
96  * and adding them to a #GActionMap.
97  *
98  * Each action is constructed as per one #GActionEntry.
99  *
100  * <example>
101  * <title>Using g_action_map_add_action_entries()</title>
102  * <programlisting>
103  * static void
104  * activate_quit (GSimpleAction *simple,
105  *                GVariant      *parameter,
106  *                gpointer       user_data)
107  * {
108  *   exit (0);
109  * }
110  *
111  * static void
112  * activate_print_string (GSimpleAction *simple,
113  *                        GVariant      *parameter,
114  *                        gpointer       user_data)
115  * {
116  *   g_print ("%s\n", g_variant_get_string (parameter, NULL));
117  * }
118  *
119  * static GActionGroup *
120  * create_action_group (void)
121  * {
122  *   const GActionEntry entries[] = {
123  *     { "quit",         activate_quit              },
124  *     { "print-string", activate_print_string, "s" }
125  *   };
126  *   GSimpleActionGroup *group;
127  *
128  *   group = g_simple_action_group_new ();
129  *   g_action_map_add_action_entries (G_ACTION_MAP (group), entries, G_N_ELEMENTS (entries), NULL);
130  *
131  *   return G_ACTION_GROUP (group);
132  * }
133  * </programlisting>
134  * </example>
135  *
136  * Since: 2.30
137  **/
138 void
139 g_action_map_add_action_entries (GActionMap         *action_map,
140                                  const GActionEntry *entries,
141                                  gint                n_entries,
142                                  gpointer            user_data)
143 {
144   gint i;
145
146   g_return_if_fail (G_IS_ACTION_MAP (action_map));
147   g_return_if_fail (entries != NULL || n_entries == 0);
148
149   for (i = 0; n_entries == -1 ? entries[i].name != NULL : i < n_entries; i++)
150     {
151       const GActionEntry *entry = &entries[i];
152       const GVariantType *parameter_type;
153       GSimpleAction *action;
154
155       if (entry->parameter_type)
156         {
157           if (!g_variant_type_string_is_valid (entry->parameter_type))
158             {
159               g_critical ("g_simple_action_group_add_entries: the type "
160                           "string '%s' given as the parameter type for "
161                           "action '%s' is not a valid GVariant type "
162                           "string.  This action will not be added.",
163                           entry->parameter_type, entry->name);
164               return;
165             }
166
167           parameter_type = G_VARIANT_TYPE (entry->parameter_type);
168         }
169       else
170         parameter_type = NULL;
171
172       if (entry->state)
173         {
174           GError *error = NULL;
175           GVariant *state;
176
177           state = g_variant_parse (NULL, entry->state, NULL, NULL, &error);
178           if (state == NULL)
179             {
180               g_critical ("g_simple_action_group_add_entries: GVariant could "
181                           "not parse the state value given for action '%s' "
182                           "('%s'): %s.  This action will not be added.",
183                           entry->name, entry->state, error->message);
184               g_error_free (error);
185               continue;
186             }
187
188           action = g_simple_action_new_stateful (entry->name,
189                                                  parameter_type,
190                                                  state);
191
192           g_variant_unref (state);
193         }
194       else
195         {
196           action = g_simple_action_new (entry->name,
197                                         parameter_type);
198         }
199
200       if (entry->activate != NULL)
201         g_signal_connect (action, "activate",
202                           G_CALLBACK (entry->activate), user_data);
203
204       if (entry->change_state != NULL)
205         g_signal_connect (action, "change-state",
206                           G_CALLBACK (entry->change_state), user_data);
207
208       g_action_map_add_action (action_map, G_ACTION (action));
209       g_object_unref (action);
210     }
211 }