2 * Copyright © 2010 Codethink Limited
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.
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.
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.
19 * Authors: Ryan Lortie <desrt@desrt.ca>
22 #include "gsimpleactiongroup.h"
24 #include "gsimpleaction.h"
28 * SECTION:gsimpleactiongroup
29 * @title: GSimpleActionGroup
30 * @short_description: A simple GActionGroup implementation
32 * #GSimpleActionGroup is a hash table filled with #GAction objects,
33 * implementing the #GActionGroup interface.
36 struct _GSimpleActionGroupPrivate
38 GHashTable *table; /* string -> GAction */
41 static void g_simple_action_group_iface_init (GActionGroupInterface *);
42 G_DEFINE_TYPE_WITH_CODE (GSimpleActionGroup,
43 g_simple_action_group, G_TYPE_OBJECT,
44 G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
45 g_simple_action_group_iface_init))
48 g_simple_action_group_list_actions (GActionGroup *group)
50 GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
56 n = g_hash_table_size (simple->priv->table);
57 keys = g_new (gchar *, n + 1);
59 g_hash_table_iter_init (&iter, simple->priv->table);
60 while (g_hash_table_iter_next (&iter, &key, NULL))
61 keys[i++] = g_strdup (key);
62 g_assert_cmpint (i, ==, n);
69 g_simple_action_group_query_action (GActionGroup *group,
70 const gchar *action_name,
72 const GVariantType **parameter_type,
73 const GVariantType **state_type,
74 GVariant **state_hint,
77 GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
80 action = g_hash_table_lookup (simple->priv->table, action_name);
86 *enabled = g_action_get_enabled (action);
89 *parameter_type = g_action_get_parameter_type (action);
92 *state_type = g_action_get_state_type (action);
95 *state_hint = g_action_get_state_hint (action);
98 *state = g_action_get_state (action);
104 g_simple_action_group_change_state (GActionGroup *group,
105 const gchar *action_name,
108 GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
111 action = g_hash_table_lookup (simple->priv->table, action_name);
116 g_action_change_state (action, value);
120 g_simple_action_group_activate (GActionGroup *group,
121 const gchar *action_name,
124 GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
127 action = g_hash_table_lookup (simple->priv->table, action_name);
132 g_action_activate (action, parameter);
136 action_enabled_notify (GAction *action,
140 g_action_group_action_enabled_changed (user_data,
141 g_action_get_name (action),
142 g_action_get_enabled (action));
146 action_state_notify (GAction *action,
152 value = g_action_get_state (action);
153 g_action_group_action_state_changed (user_data,
154 g_action_get_name (action),
156 g_variant_unref (value);
160 g_simple_action_group_disconnect (gpointer key,
164 g_signal_handlers_disconnect_by_func (value, action_enabled_notify,
166 g_signal_handlers_disconnect_by_func (value, action_state_notify,
171 g_simple_action_group_finalize (GObject *object)
173 GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (object);
175 g_hash_table_foreach (simple->priv->table,
176 g_simple_action_group_disconnect,
178 g_hash_table_unref (simple->priv->table);
180 G_OBJECT_CLASS (g_simple_action_group_parent_class)
185 g_simple_action_group_init (GSimpleActionGroup *simple)
187 simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (simple,
188 G_TYPE_SIMPLE_ACTION_GROUP,
189 GSimpleActionGroupPrivate);
190 simple->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
191 g_free, g_object_unref);
195 g_simple_action_group_class_init (GSimpleActionGroupClass *class)
197 GObjectClass *object_class = G_OBJECT_CLASS (class);
199 object_class->finalize = g_simple_action_group_finalize;
201 g_type_class_add_private (class, sizeof (GSimpleActionGroupPrivate));
205 g_simple_action_group_iface_init (GActionGroupInterface *iface)
207 iface->list_actions = g_simple_action_group_list_actions;
208 iface->query_action = g_simple_action_group_query_action;
209 iface->change_action_state = g_simple_action_group_change_state;
210 iface->activate_action = g_simple_action_group_activate;
214 * g_simple_action_group_new:
216 * Creates a new, empty, #GSimpleActionGroup.
218 * Returns: a new #GSimpleActionGroup
223 g_simple_action_group_new (void)
225 return g_object_new (G_TYPE_SIMPLE_ACTION_GROUP, NULL);
229 * g_simple_action_group_lookup:
230 * @simple: a #GSimpleActionGroup
231 * @action_name: the name of an action
233 * Looks up the action with the name @action_name in the group.
235 * If no such action exists, returns %NULL.
237 * Returns: (transfer none): a #GAction, or %NULL
242 g_simple_action_group_lookup (GSimpleActionGroup *simple,
243 const gchar *action_name)
245 g_return_val_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple), NULL);
247 return g_hash_table_lookup (simple->priv->table, action_name);
251 * g_simple_action_group_insert:
252 * @simple: a #GSimpleActionGroup
253 * @action: a #GAction
255 * Adds an action to the action group.
257 * If the action group already contains an action with the same name as
258 * @action then the old action is dropped from the group.
260 * The action group takes its own reference on @action.
265 g_simple_action_group_insert (GSimpleActionGroup *simple,
268 const gchar *action_name;
271 g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
272 g_return_if_fail (G_IS_ACTION (action));
274 action_name = g_action_get_name (action);
275 old_action = g_hash_table_lookup (simple->priv->table, action_name);
277 if (old_action != action)
279 if (old_action != NULL)
281 g_action_group_action_removed (G_ACTION_GROUP (simple),
283 g_simple_action_group_disconnect (NULL, old_action, simple);
286 g_signal_connect (action, "notify::enabled",
287 G_CALLBACK (action_enabled_notify), simple);
289 if (g_action_get_state_type (action) != NULL)
290 g_signal_connect (action, "notify::state",
291 G_CALLBACK (action_state_notify), simple);
293 g_hash_table_insert (simple->priv->table,
294 g_strdup (action_name),
295 g_object_ref (action));
297 g_action_group_action_added (G_ACTION_GROUP (simple), action_name);
302 * g_simple_action_group_remove:
303 * @simple: a #GSimpleActionGroup
304 * @action_name: the name of the action
306 * Removes the named action from the action group.
308 * If no action of this name is in the group then nothing happens.
313 g_simple_action_group_remove (GSimpleActionGroup *simple,
314 const gchar *action_name)
318 g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
320 action = g_hash_table_lookup (simple->priv->table, action_name);
324 g_action_group_action_removed (G_ACTION_GROUP (simple), action_name);
325 g_simple_action_group_disconnect (NULL, action, simple);
326 g_hash_table_remove (simple->priv->table, action_name);
332 * @name: the name of the action
333 * @activate: the callback to connect to the "activate" signal of the
335 * @parameter_type: the type of the parameter that must be passed to the
336 * activate function for this action, given as a single
337 * GVariant type string (or %NULL for no parameter)
338 * @state: the initial state for this action, given in GVariant text
339 * format. The state is parsed with no extra type information,
340 * so type tags must be added to the string if they are
342 * @change_state: the callback to connect to the "change-state" signal
345 * This struct defines a single action. It is for use with
346 * g_simple_action_group_add_entries().
348 * The order of the items in the structure are intended to reflect
349 * frequency of use. It is permissible to use an incomplete initialiser
350 * in order to leave some of the later values as %NULL. All values
351 * after @name are optional. Additional optional fields may be added in
354 * See g_simple_action_group_add_entries() for an example.
358 * g_simple_action_group_add_entries:
359 * @simple: a #GSimpleActionGroup
360 * @entries: a pointer to the first item in an array of #GActionEntry
362 * @n_entries: the length of @entries, or -1
363 * @user_data: the user data for signal connections
365 * A convenience function for creating multiple #GSimpleAction instances
366 * and adding them to the action group.
368 * Each action is constructed as per one #GActionEntry.
371 * <title>Using g_simple_action_group_add_entries()</title>
374 * activate_quit (GSimpleAction *simple,
375 * GVariant *parameter,
376 * gpointer user_data)
382 * activate_print_string (GSimpleAction *simple,
383 * GVariant *parameter,
384 * gpointer user_data)
386 * g_print ("%s\n", g_variant_get_string (parameter, NULL));
389 * static GActionGroup *
390 * create_action_group (void)
392 * const GActionEntry entries[] = {
393 * { "quit", activate_quit },
394 * { "print-string", activate_print_string, "s" }
396 * GSimpleActionGroup *group;
398 * group = g_simple_action_group_new ();
399 * g_simple_action_group_add_entries (group, entries, G_N_ELEMENTS (entries), NULL);
401 * return G_ACTION_GROUP (group);
409 g_simple_action_group_add_entries (GSimpleActionGroup *simple,
410 const GActionEntry *entries,
416 g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
417 g_return_if_fail (entries != NULL || n_entries == 0);
419 for (i = 0; n_entries == -1 ? entries[i].name != NULL : i < n_entries; i++)
421 const GActionEntry *entry = &entries[i];
422 const GVariantType *parameter_type;
423 GSimpleAction *action;
425 if (entry->parameter_type)
427 if (!g_variant_type_string_is_valid (entry->parameter_type))
429 g_critical ("g_simple_action_group_add_entries: the type "
430 "string '%s' given as the parameter type for "
431 "action '%s' is not a valid GVariant type "
432 "string. This action will not be added.",
433 entry->parameter_type, entry->name);
437 parameter_type = G_VARIANT_TYPE (entry->parameter_type);
440 parameter_type = NULL;
444 GError *error = NULL;
447 state = g_variant_parse (NULL, entry->state, NULL, NULL, &error);
450 g_critical ("g_simple_action_group_add_entries: GVariant could "
451 "not parse the state value given for action '%s' "
452 "('%s'): %s. This action will not be added.",
453 entry->name, entry->state, error->message);
454 g_error_free (error);
458 action = g_simple_action_new_stateful (entry->name,
462 g_variant_unref (state);
466 action = g_simple_action_new (entry->name,
470 if (entry->activate != NULL)
471 g_signal_connect (action, "activate",
472 G_CALLBACK (entry->activate), user_data);
474 if (entry->change_state != NULL)
475 g_signal_connect (action, "change-state",
476 G_CALLBACK (entry->change_state), user_data);
478 g_simple_action_group_insert (simple, G_ACTION (action));
479 g_object_unref (action);