Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gactionmap.c
Line
Count
Source (jump to first uncovered line)
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
 * GActionMap:
30
 *
31
 * `GActionMap` is an interface for action containers.
32
 *
33
 * The `GActionMap` interface is implemented by [iface@Gio.ActionGroup]
34
 * implementations that operate by containing a number of named
35
 * [iface@Gio.Action] instances, such as [class@Gio.SimpleActionGroup].
36
 *
37
 * One useful application of this interface is to map the
38
 * names of actions from various action groups to unique,
39
 * prefixed names (e.g. by prepending "app." or "win.").
40
 * This is the motivation for the ‘Map’ part of the interface
41
 * name.
42
 *
43
 * Since: 2.32
44
 */
45
46
/**
47
 * GActionMapInterface:
48
 * @lookup_action: the virtual function pointer for
49
 *   [method@Gio.ActionMap.lookup_action]
50
 * @add_action: the virtual function pointer for
51
 *   [method@Gio.ActionMap.add_action]
52
 * @remove_action: the virtual function pointer for
53
 *   [method@Gio.ActionMap.remove_action]
54
 *
55
 * The virtual function table for [iface@Gio.ActionMap].
56
 *
57
 * Since: 2.32
58
 **/
59
60
G_DEFINE_INTERFACE (GActionMap, g_action_map, G_TYPE_OBJECT)
61
62
static void
63
g_action_map_default_init (GActionMapInterface *iface)
64
0
{
65
0
}
66
67
/**
68
 * g_action_map_lookup_action:
69
 * @action_map: an action map
70
 * @action_name: the name of an action
71
 *
72
 * Looks up the action with the name @action_name in @action_map.
73
 *
74
 * If no such action exists, returns `NULL`.
75
 *
76
 * Returns: (nullable) (transfer none): a [iface@Gio.Action]
77
 *
78
 * Since: 2.32
79
 */
80
GAction *
81
g_action_map_lookup_action (GActionMap  *action_map,
82
                            const gchar *action_name)
83
0
{
84
0
  return G_ACTION_MAP_GET_IFACE (action_map)
85
0
    ->lookup_action (action_map, action_name);
86
0
}
87
88
/**
89
 * g_action_map_add_action:
90
 * @action_map: an action map
91
 * @action: a [iface@Gio.Action]
92
 *
93
 * Adds an action to the @action_map.
94
 *
95
 * If the action map already contains an action with the same name
96
 * as @action then the old action is dropped from the action map.
97
 *
98
 * The action map takes its own reference on @action.
99
 *
100
 * Since: 2.32
101
 */
102
void
103
g_action_map_add_action (GActionMap *action_map,
104
                         GAction    *action)
105
0
{
106
0
  G_ACTION_MAP_GET_IFACE (action_map)->add_action (action_map, action);
107
0
}
108
109
/**
110
 * g_action_map_remove_action:
111
 * @action_map: an action map
112
 * @action_name: the name of the action
113
 *
114
 * Removes the named action from the action map.
115
 *
116
 * If no action of this name is in the map then nothing happens.
117
 *
118
 * Since: 2.32
119
 */
120
void
121
g_action_map_remove_action (GActionMap  *action_map,
122
                            const gchar *action_name)
123
0
{
124
0
  G_ACTION_MAP_GET_IFACE (action_map)->remove_action (action_map, action_name);
125
0
}
126
127
/**
128
 * GActionEntry:
129
 * @name: the name of the action
130
 * @activate: the callback to connect to the "activate" signal of the action.
131
 *   Since GLib 2.40, this can be `NULL` for stateful actions, in which case
132
 *   the default handler is used. For boolean-stated actions with no
133
 *   parameter, this is a toggle. For other state types (and parameter type
134
 *   equal to the state type) this will be a function that just calls
135
 *   @change_state (which you should provide).
136
 * @parameter_type: the type of the parameter that must be passed to the
137
 *   activate function for this action, given as a single GVariant type string
138
 *   (or `NULL` for no parameter)
139
 * @state: the initial state for this action, given in
140
 *   [GVariant text format](../glib/gvariant-text-format.html).  The state is parsed
141
 *   with no extra type information, so type tags must be added to the string
142
 *   if they are necessary.  Stateless actions should give `NULL` here.
143
 * @change_state: the callback to connect to the "change-state" signal of the
144
 *   action.  All stateful actions should provide a handler here; stateless
145
 *   actions should not.
146
 *
147
 * This struct defines a single action.  It is for use with
148
 * [method@Gio.ActionMap.add_action_entries].
149
 *
150
 * The order of the items in the structure are intended to reflect
151
 * frequency of use.  It is permissible to use an incomplete initialiser
152
 * in order to leave some of the later values as `NULL`.  All values
153
 * after @name are optional.  Additional optional fields may be added in
154
 * the future.
155
 *
156
 * See [method@Gio.ActionMap.add_action_entries] for an example.
157
 **/
158
159
/**
160
 * g_action_map_add_action_entries:
161
 * @action_map: an action map
162
 * @entries: (array length=n_entries) (element-type GActionEntry): a pointer to
163
 *   the first item in an array of [struct@Gio.ActionEntry] structs
164
 * @n_entries: the length of @entries, or -1 if @entries is `NULL`-terminated
165
 * @user_data: the user data for signal connections
166
 *
167
 * A convenience function for creating multiple [class@Gio.SimpleAction]
168
 * instances and adding them to a [iface@Gio.ActionMap].
169
 *
170
 * Each action is constructed as per one [struct@Gio.ActionEntry].
171
 *
172
 * ```c
173
 * static void
174
 * activate_quit (GSimpleAction *simple,
175
 *                GVariant      *parameter,
176
 *                gpointer       user_data)
177
 * {
178
 *   exit (0);
179
 * }
180
 *
181
 * static void
182
 * activate_print_string (GSimpleAction *simple,
183
 *                        GVariant      *parameter,
184
 *                        gpointer       user_data)
185
 * {
186
 *   g_print ("%s\n", g_variant_get_string (parameter, NULL));
187
 * }
188
 *
189
 * static GActionGroup *
190
 * create_action_group (void)
191
 * {
192
 *   const GActionEntry entries[] = {
193
 *     { "quit",         activate_quit              },
194
 *     { "print-string", activate_print_string, "s" }
195
 *   };
196
 *   GSimpleActionGroup *group;
197
 *
198
 *   group = g_simple_action_group_new ();
199
 *   g_action_map_add_action_entries (G_ACTION_MAP (group), entries, G_N_ELEMENTS (entries), NULL);
200
 *
201
 *   return G_ACTION_GROUP (group);
202
 * }
203
 * ```
204
 *
205
 * Since: 2.32
206
 */
207
void
208
g_action_map_add_action_entries (GActionMap         *action_map,
209
                                 const GActionEntry *entries,
210
                                 gint                n_entries,
211
                                 gpointer            user_data)
212
0
{
213
0
  g_return_if_fail (G_IS_ACTION_MAP (action_map));
214
0
  g_return_if_fail (entries != NULL || n_entries == 0);
215
216
0
  for (int i = 0; n_entries < 0 ? entries[i].name != NULL : i < n_entries; i++)
217
0
    {
218
0
      const GActionEntry *entry = &entries[i];
219
0
      const GVariantType *parameter_type;
220
0
      GSimpleAction *action;
221
222
0
      if (entry->parameter_type)
223
0
        {
224
0
          if (!g_variant_type_string_is_valid (entry->parameter_type))
225
0
            {
226
0
              g_critical ("g_action_map_add_entries: the type "
227
0
                          "string '%s' given as the parameter type for "
228
0
                          "action '%s' is not a valid GVariant type "
229
0
                          "string.  This action will not be added.",
230
0
                          entry->parameter_type, entry->name);
231
0
              return;
232
0
            }
233
234
0
          parameter_type = G_VARIANT_TYPE (entry->parameter_type);
235
0
        }
236
0
      else
237
0
        parameter_type = NULL;
238
239
0
      if (entry->state)
240
0
        {
241
0
          GError *error = NULL;
242
0
          GVariant *state;
243
244
0
          state = g_variant_parse (NULL, entry->state, NULL, NULL, &error);
245
0
          if (state == NULL)
246
0
            {
247
0
              g_critical ("g_action_map_add_entries: GVariant could "
248
0
                          "not parse the state value given for action '%s' "
249
0
                          "('%s'): %s.  This action will not be added.",
250
0
                          entry->name, entry->state, error->message);
251
0
              g_error_free (error);
252
0
              continue;
253
0
            }
254
255
0
          action = g_simple_action_new_stateful (entry->name,
256
0
                                                 parameter_type,
257
0
                                                 state);
258
259
0
          g_variant_unref (state);
260
0
        }
261
0
      else
262
0
        {
263
0
          action = g_simple_action_new (entry->name,
264
0
                                        parameter_type);
265
0
        }
266
267
0
      if (entry->activate != NULL)
268
0
        g_signal_connect (action, "activate",
269
0
                          G_CALLBACK (entry->activate), user_data);
270
271
0
      if (entry->change_state != NULL)
272
0
        g_signal_connect (action, "change-state",
273
0
                          G_CALLBACK (entry->change_state), user_data);
274
275
0
      g_action_map_add_action (action_map, G_ACTION (action));
276
0
      g_object_unref (action);
277
0
    }
278
0
}
279
280
/**
281
 * g_action_map_remove_action_entries:
282
 * @action_map: The [iface@Gio.ActionMap]
283
 * @entries: (array length=n_entries) (element-type GActionEntry): a pointer to
284
 *   the first item in an array of [struct@Gio.ActionEntry] structs
285
 * @n_entries: the length of @entries, or -1 if @entries is `NULL`-terminated
286
 *
287
 * Remove actions from a [iface@Gio.ActionMap]. This is meant as the reverse of
288
 * [method@Gio.ActionMap.add_action_entries].
289
 *
290
 *
291
 * ```c
292
 * static const GActionEntry entries[] = {
293
 *     { "quit",         activate_quit              },
294
 *     { "print-string", activate_print_string, "s" }
295
 * };
296
 *
297
 * void
298
 * add_actions (GActionMap *map)
299
 * {
300
 *   g_action_map_add_action_entries (map, entries, G_N_ELEMENTS (entries), NULL);
301
 * }
302
 *
303
 * void
304
 * remove_actions (GActionMap *map)
305
 * {
306
 *   g_action_map_remove_action_entries (map, entries, G_N_ELEMENTS (entries));
307
 * }
308
 * ```
309
 *
310
 * Since: 2.78
311
 */
312
void
313
g_action_map_remove_action_entries (GActionMap         *action_map,
314
                                    const GActionEntry  entries[],
315
                                    gint                n_entries)
316
0
{
317
0
  g_return_if_fail (G_IS_ACTION_MAP (action_map));
318
0
  g_return_if_fail (entries != NULL || n_entries == 0);
319
320
0
  for (int i = 0; n_entries < 0 ? entries[i].name != NULL : i < n_entries; i++)
321
0
    g_action_map_remove_action (action_map, entries[i].name);
322
0
}