kdbus: Fixup signal subscription
[platform/upstream/glib.git] / gio / gactionmap.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General
17  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gsimpleaction.h"
25 #include "gactionmap.h"
26 #include "gaction.h"
27
28 /**
29  * SECTION:gactionmap
30  * @title: GActionMap
31  * @include: gio/gio.h
32  * @short_description: Interface for action containers
33  *
34  * The GActionMap interface is implemented by #GActionGroup
35  * implementations that operate by containing a number of
36  * named #GAction instances, such as #GSimpleActionGroup.
37  *
38  * One useful application of this interface is to map the
39  * names of actions from various action groups to unique,
40  * prefixed names (e.g. by prepending "app." or "win.").
41  * This is the motivation for the 'Map' part of the interface
42  * name.
43  *
44  * Since: 2.32
45  **/
46
47 /**
48  * GActionMap:
49  *
50  * #GActionMap is an opaque data structure and can only be accessed
51  * using the following functions.
52  **/
53
54 /**
55  * GActionMapInterface:
56  * @lookup_action: the virtual function pointer for g_action_map_lookup_action()
57  * @add_action: the virtual function pointer for g_action_map_add_action()
58  * @remove_action: the virtual function pointer for g_action_map_remove_action()
59  *
60  * The virtual function table for #GActionMap.
61  *
62  * Since: 2.32
63  **/
64
65 G_DEFINE_INTERFACE (GActionMap, g_action_map, G_TYPE_OBJECT)
66
67 static void
68 g_action_map_default_init (GActionMapInterface *iface)
69 {
70 }
71
72 /**
73  * g_action_map_lookup_action:
74  * @action_map: a #GActionMap
75  * @action_name: the name of an action
76  *
77  * Looks up the action with the name @action_name in @action_map.
78  *
79  * If no such action exists, returns %NULL.
80  *
81  * Returns: (nullable) (transfer none): a #GAction, or %NULL
82  *
83  * Since: 2.32
84  */
85 GAction *
86 g_action_map_lookup_action (GActionMap  *action_map,
87                             const gchar *action_name)
88 {
89   return G_ACTION_MAP_GET_IFACE (action_map)
90     ->lookup_action (action_map, action_name);
91 }
92
93 /**
94  * g_action_map_add_action:
95  * @action_map: a #GActionMap
96  * @action: a #GAction
97  *
98  * Adds an action to the @action_map.
99  *
100  * If the action map already contains an action with the same name
101  * as @action then the old action is dropped from the action map.
102  *
103  * The action map takes its own reference on @action.
104  *
105  * Since: 2.32
106  */
107 void
108 g_action_map_add_action (GActionMap *action_map,
109                          GAction    *action)
110 {
111   G_ACTION_MAP_GET_IFACE (action_map)->add_action (action_map, action);
112 }
113
114 /**
115  * g_action_map_remove_action:
116  * @action_map: a #GActionMap
117  * @action_name: the name of the action
118  *
119  * Removes the named action from the action map.
120  *
121  * If no action of this name is in the map then nothing happens.
122  *
123  * Since: 2.32
124  */
125 void
126 g_action_map_remove_action (GActionMap  *action_map,
127                             const gchar *action_name)
128 {
129   G_ACTION_MAP_GET_IFACE (action_map)->remove_action (action_map, action_name);
130 }
131
132 /**
133  * GActionEntry:
134  * @name: the name of the action
135  * @activate: the callback to connect to the "activate" signal of the
136  *            action.  Since GLib 2.40, this can be %NULL for stateful
137  *            actions, in which case the default handler is used.  For
138  *            boolean-stated actions with no parameter, this is a
139  *            toggle.  For other state types (and parameter type equal
140  *            to the state type) this will be a function that
141  *            just calls @change_state (which you should provide).
142  * @parameter_type: the type of the parameter that must be passed to the
143  *                  activate function for this action, given as a single
144  *                  GVariant type string (or %NULL for no parameter)
145  * @state: the initial state for this action, given in
146  *         [GVariant text format][gvariant-text].  The state is parsed
147  *         with no extra type information, so type tags must be added to
148  *         the string if they are necessary.  Stateless actions should
149  *         give %NULL here.
150  * @change_state: the callback to connect to the "change-state" signal
151  *                of the action.  All stateful actions should provide a
152  *                handler here; stateless actions should not.
153  *
154  * This struct defines a single action.  It is for use with
155  * g_action_map_add_action_entries().
156  *
157  * The order of the items in the structure are intended to reflect
158  * frequency of use.  It is permissible to use an incomplete initialiser
159  * in order to leave some of the later values as %NULL.  All values
160  * after @name are optional.  Additional optional fields may be added in
161  * the future.
162  *
163  * See g_action_map_add_action_entries() for an example.
164  **/
165
166 /**
167  * g_action_map_add_action_entries:
168  * @action_map: a #GActionMap
169  * @entries: (array length=n_entries) (element-type GActionEntry): a pointer to
170  *           the first item in an array of #GActionEntry structs
171  * @n_entries: the length of @entries, or -1 if @entries is %NULL-terminated
172  * @user_data: the user data for signal connections
173  *
174  * A convenience function for creating multiple #GSimpleAction instances
175  * and adding them to a #GActionMap.
176  *
177  * Each action is constructed as per one #GActionEntry.
178  *
179  * |[<!-- language="C" -->
180  * static void
181  * activate_quit (GSimpleAction *simple,
182  *                GVariant      *parameter,
183  *                gpointer       user_data)
184  * {
185  *   exit (0);
186  * }
187  *
188  * static void
189  * activate_print_string (GSimpleAction *simple,
190  *                        GVariant      *parameter,
191  *                        gpointer       user_data)
192  * {
193  *   g_print ("%s\n", g_variant_get_string (parameter, NULL));
194  * }
195  *
196  * static GActionGroup *
197  * create_action_group (void)
198  * {
199  *   const GActionEntry entries[] = {
200  *     { "quit",         activate_quit              },
201  *     { "print-string", activate_print_string, "s" }
202  *   };
203  *   GSimpleActionGroup *group;
204  *
205  *   group = g_simple_action_group_new ();
206  *   g_action_map_add_action_entries (G_ACTION_MAP (group), entries, G_N_ELEMENTS (entries), NULL);
207  *
208  *   return G_ACTION_GROUP (group);
209  * }
210  * ]|
211  *
212  * Since: 2.32
213  */
214 void
215 g_action_map_add_action_entries (GActionMap         *action_map,
216                                  const GActionEntry *entries,
217                                  gint                n_entries,
218                                  gpointer            user_data)
219 {
220   g_return_if_fail (G_IS_ACTION_MAP (action_map));
221   g_return_if_fail (entries != NULL || n_entries == 0);
222
223   for (int i = 0; n_entries < 0 ? entries[i].name != NULL : i < n_entries; i++)
224     {
225       const GActionEntry *entry = &entries[i];
226       const GVariantType *parameter_type;
227       GSimpleAction *action;
228
229       if (entry->parameter_type)
230         {
231           if (!g_variant_type_string_is_valid (entry->parameter_type))
232             {
233               g_critical ("g_action_map_add_entries: the type "
234                           "string '%s' given as the parameter type for "
235                           "action '%s' is not a valid GVariant type "
236                           "string.  This action will not be added.",
237                           entry->parameter_type, entry->name);
238               return;
239             }
240
241           parameter_type = G_VARIANT_TYPE (entry->parameter_type);
242         }
243       else
244         parameter_type = NULL;
245
246       if (entry->state)
247         {
248           GError *error = NULL;
249           GVariant *state;
250
251           state = g_variant_parse (NULL, entry->state, NULL, NULL, &error);
252           if (state == NULL)
253             {
254               g_critical ("g_action_map_add_entries: GVariant could "
255                           "not parse the state value given for action '%s' "
256                           "('%s'): %s.  This action will not be added.",
257                           entry->name, entry->state, error->message);
258               g_error_free (error);
259               continue;
260             }
261
262           action = g_simple_action_new_stateful (entry->name,
263                                                  parameter_type,
264                                                  state);
265
266           g_variant_unref (state);
267         }
268       else
269         {
270           action = g_simple_action_new (entry->name,
271                                         parameter_type);
272         }
273
274       if (entry->activate != NULL)
275         g_signal_connect (action, "activate",
276                           G_CALLBACK (entry->activate), user_data);
277
278       if (entry->change_state != NULL)
279         g_signal_connect (action, "change-state",
280                           G_CALLBACK (entry->change_state), user_data);
281
282       g_action_map_add_action (action_map, G_ACTION (action));
283       g_object_unref (action);
284     }
285 }
286
287 /**
288  * g_action_map_remove_action_entries:
289  * @action_map: The #GActionMap
290  * @entries: (array length=n_entries) (element-type GActionEntry): a pointer to
291  *           the first item in an array of #GActionEntry structs
292  * @n_entries: the length of @entries, or -1 if @entries is %NULL-terminated
293  *
294  * Remove actions from a #GActionMap. This is meant as the reverse of
295  * g_action_map_add_action_entries().
296  *
297  *
298  * |[<!-- language="C" -->
299  * static const GActionEntry entries[] = {
300  *     { "quit",         activate_quit              },
301  *     { "print-string", activate_print_string, "s" }
302  * };
303  *
304  * void
305  * add_actions (GActionMap *map)
306  * {
307  *   g_action_map_add_action_entries (map, entries, G_N_ELEMENTS (entries), NULL);
308  * }
309  *
310  * void
311  * remove_actions (GActionMap *map)
312  * {
313  *   g_action_map_remove_action_entries (map, entries, G_N_ELEMENTS (entries));
314  * }
315  * ]|
316  *
317  * Since: 2.78
318  */
319 void
320 g_action_map_remove_action_entries (GActionMap         *action_map,
321                                     const GActionEntry  entries[],
322                                     gint                n_entries)
323 {
324   g_return_if_fail (G_IS_ACTION_MAP (action_map));
325   g_return_if_fail (entries != NULL || n_entries == 0);
326
327   for (int i = 0; n_entries < 0 ? entries[i].name != NULL : i < n_entries; i++)
328     g_action_map_remove_action (action_map, entries[i].name);
329 }