From 5db9e5ad58040b5ccdba73c59a76522f9c35aa34 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Wed, 18 Aug 2010 02:15:09 -0400 Subject: [PATCH] add GSimpleActionGroup and a simple test --- docs/reference/gio/gio-docs.xml | 1 + docs/reference/gio/gio-sections.txt | 28 ++ docs/reference/gio/gio.types | 1 + gio/Makefile.am | 2 + gio/gio.h | 1 + gio/giotypes.h | 1 + gio/gsimpleactiongroup.c | 401 ++++++++++++++++++++++++++++ gio/gsimpleactiongroup.h | 91 +++++++ gio/tests/actions.c | 28 ++ 9 files changed, 554 insertions(+) create mode 100644 gio/gsimpleactiongroup.c create mode 100644 gio/gsimpleactiongroup.h diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index 69381cd77..9fea7a398 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -163,6 +163,7 @@ Application support + diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index af4bbfca8..a03ca710b 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -2738,3 +2738,31 @@ G_ACTION_GET_CLASS G_IS_ACTION_CLASS G_ACTION + +
+gsimpleactiongroup +GSimpleActionGroup +GSimpleActionGroup + + +g_simple_action_group_new + + +g_simple_action_group_lookup +g_simple_action_group_insert +g_simple_action_group_remove + + +g_simple_action_group_set_enabled + + +GSimpleActionGroupClass +GSimpleActionGroupPrivate +g_simple_action_group_get_type +G_TYPE_SIMPLE_ACTION_GROUP +G_IS_SIMPLE_ACTION_GROUP +G_SIMPLE_ACTION_GROUP_CLASS +G_SIMPLE_ACTION_GROUP_GET_CLASS +G_IS_SIMPLE_ACTION_GROUP_CLASS +G_SIMPLE_ACTION_GROUP +
diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types index fa07b3ea0..7d208ddee 100644 --- a/docs/reference/gio/gio.types +++ b/docs/reference/gio/gio.types @@ -1,5 +1,6 @@ g_action_get_type g_action_group_get_type +g_simple_action_group_get_type g_app_info_create_flags_get_type g_app_info_get_type g_app_launch_context_get_type diff --git a/gio/Makefile.am b/gio/Makefile.am index 3240dbbec..8cff34f2c 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -130,11 +130,13 @@ settings_sources = \ application_headers = \ gactiongroup.h \ + gsimpleactiongroup.h \ gaction.h \ gapplication.h application_sources = \ gactiongroup.c \ + gsimpleactiongroup.c \ gaction.c \ gapplication.c diff --git a/gio/gio.h b/gio/gio.h index 0098df40a..e5f8f9ef5 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/gio/giotypes.h b/gio/giotypes.h index 9b10854f3..ff48a3872 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -47,6 +47,7 @@ typedef struct _GSimplePermission GSimplePermission; typedef struct _GZlibCompressor GZlibCompressor; typedef struct _GZlibDecompressor GZlibDecompressor; +typedef struct _GSimpleActionGroup GSimpleActionGroup; typedef struct _GActionGroup GActionGroup; typedef struct _GAction GAction; typedef struct _GSettingsBackend GSettingsBackend; diff --git a/gio/gsimpleactiongroup.c b/gio/gsimpleactiongroup.c new file mode 100644 index 000000000..dc3451d60 --- /dev/null +++ b/gio/gsimpleactiongroup.c @@ -0,0 +1,401 @@ +/* + * Copyright © 2010 Codethink Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Ryan Lortie + */ + +#include "gsimpleactiongroup.h" +#include "gaction.h" + +/** + * SECTION:gsimpleactiongroup + * @title: GSimpleActionGroup + * @short_description: a simple #GActionGroup implementation + * + * #GSimpleActionGroup is a hash table filled with #GAction objects, + * implementing the #GActionGroup interface. + **/ + +struct _GSimpleActionGroupPrivate +{ + GHashTable *table; /* string -> GAction */ +}; + +G_DEFINE_TYPE (GSimpleActionGroup, g_simple_action_group, G_TYPE_ACTION_GROUP) + +static gchar ** +g_simple_action_group_list_actions (GActionGroup *group) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GHashTableIter iter; + gint n, i = 0; + gchar **keys; + gpointer key; + + n = g_hash_table_size (simple->priv->table); + keys = g_new (gchar *, n + 1); + + g_hash_table_iter_init (&iter, simple->priv->table); + while (g_hash_table_iter_next (&iter, &key, NULL)) + keys[i++] = g_strdup (key); + g_assert_cmpint (i, ==, n); + keys[n] = NULL; + + return keys; +} + +static gboolean +g_simple_action_group_has_action (GActionGroup *group, + const gchar *action_name) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + + return g_hash_table_lookup (simple->priv->table, action_name) != NULL; +} + +static const GVariantType * +g_simple_action_group_get_parameter_type (GActionGroup *group, + const gchar *action_name) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return NULL; + + return g_action_get_parameter_type (action); +} + +static const GVariantType * +g_simple_action_group_get_state_type (GActionGroup *group, + const gchar *action_name) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return NULL; + + return g_action_get_state_type (action); +} + +static GVariant * +g_simple_action_group_get_state_hint (GActionGroup *group, + const gchar *action_name) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return NULL; + + return g_action_get_state_hint (action); +} + +static gboolean +g_simple_action_group_get_enabled (GActionGroup *group, + const gchar *action_name) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return FALSE; + + return g_action_get_enabled (action); +} + +static GVariant * +g_simple_action_group_get_state (GActionGroup *group, + const gchar *action_name) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return NULL; + + return g_action_get_state (action); +} + +static void +g_simple_action_group_set_state (GActionGroup *group, + const gchar *action_name, + GVariant *value) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return; + + return g_action_set_state (action, value); +} + +static void +g_simple_action_group_activate (GActionGroup *group, + const gchar *action_name, + GVariant *parameter) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); + GAction *action; + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action == NULL) + return; + + return g_action_activate (action, parameter); +} + +static void +action_enabled_changed (GAction *action, + gboolean enabled, + gpointer user_data) +{ + g_action_group_action_enabled_changed (user_data, + g_action_get_name (action), + enabled); +} + +static void +action_state_changed (GAction *action, + GVariant *value, + gpointer user_data) +{ + g_action_group_action_state_changed (user_data, + g_action_get_name (action), + value); +} + +static void +g_simple_action_group_disconnect (gpointer key, + gpointer value, + gpointer user_data) +{ + g_signal_handlers_disconnect_by_func (value, action_enabled_changed, + user_data); + g_signal_handlers_disconnect_by_func (value, action_state_changed, + user_data); +} + +static void +g_simple_action_group_finalize (GObject *object) +{ + GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (object); + + g_hash_table_foreach (simple->priv->table, + g_simple_action_group_disconnect, + simple); + g_hash_table_unref (simple->priv->table); + + G_OBJECT_CLASS (g_simple_action_group_parent_class) + ->finalize (object); +} + +static void +g_simple_action_group_init (GSimpleActionGroup *simple) +{ + simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (simple, + G_TYPE_SIMPLE_ACTION_GROUP, + GSimpleActionGroupPrivate); + simple->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); +} + +static void +g_simple_action_group_class_init (GSimpleActionGroupClass *class) +{ + GActionGroupClass *group_class = G_ACTION_GROUP_CLASS (class); + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = g_simple_action_group_finalize; + + group_class->list_actions = g_simple_action_group_list_actions; + group_class->has_action = g_simple_action_group_has_action; + group_class->get_parameter_type = g_simple_action_group_get_parameter_type; + group_class->get_state_type = g_simple_action_group_get_state_type; + group_class->get_state_hint = g_simple_action_group_get_state_hint; + group_class->get_enabled = g_simple_action_group_get_enabled; + group_class->get_state = g_simple_action_group_get_state; + group_class->set_state = g_simple_action_group_set_state; + group_class->activate = g_simple_action_group_activate; + + g_type_class_add_private (class, sizeof (GSimpleActionGroupPrivate)); +} + +/** + * g_simple_action_group_new: + * + * Creates a new, empty, #GSimpleActionGroup. + * + * Returns: a new #GSimpleActionGroup + * + * Since: 2.26 + **/ +GSimpleActionGroup * +g_simple_action_group_new (void) +{ + return g_object_new (G_TYPE_SIMPLE_ACTION_GROUP, NULL); +} + +/** + * g_simple_action_group_lookup: + * @simple: a #GSimpleActionGroup + * @action_name: the name of an action + * + * Looks up the action with the name @action_name in the group. + * + * If no such action exists, returns %NULL. + * + * Returns: (transfer none): a #GAction, or %NULL + * + * Since: 2.26 + **/ +GAction * +g_simple_action_group_lookup (GSimpleActionGroup *simple, + const gchar *action_name) +{ + g_return_val_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple), NULL); + + return g_hash_table_lookup (simple->priv->table, action_name); +} + +/** + * g_simple_action_group_insert: + * @simple: a #GSimpleActionGroup + * @action: a #GAction + * + * Adds an action to the action group. + * + * If the action group already contains an action with the same name as + * @action then the old action is dropped from the group. + * + * The action group takes its own reference on @action. + * + * Since: 2.26 + **/ +void +g_simple_action_group_insert (GSimpleActionGroup *simple, + GAction *action) +{ + const gchar *action_name; + GAction *old_action; + + g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple)); + g_return_if_fail (G_IS_ACTION (action)); + + action_name = g_action_get_name (action); + old_action = g_hash_table_lookup (simple->priv->table, action_name); + + if (old_action != action) + { + if (old_action != NULL) + { + g_action_group_action_removed (G_ACTION_GROUP (simple), + action_name); + g_simple_action_group_disconnect (NULL, old_action, simple); + } + + g_signal_connect (action, "notify::enabled", + G_CALLBACK (action_enabled_changed), simple); + + if (g_action_get_state_type (action) != NULL) + g_signal_connect (action, "notify::state", + G_CALLBACK (action_state_changed), simple); + + g_hash_table_insert (simple->priv->table, + g_strdup (action_name), + g_object_ref (action)); + + g_action_group_action_added (G_ACTION_GROUP (simple), action_name); + } +} + +/** + * g_simple_action_group_remove: + * @simple: a #GSimpleActionGroup + * @action_name: the name of the action + * + * Removes the named action from the action group. + * + * If no action of this name is in the group then nothing happens. + * + * Since: 2.26 + **/ +void +g_simple_action_group_remove (GSimpleActionGroup *simple, + const gchar *action_name) +{ + GAction *action; + + g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple)); + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action != NULL) + { + g_action_group_action_removed (G_ACTION_GROUP (simple), action_name); + g_simple_action_group_disconnect (NULL, action, simple); + g_hash_table_remove (simple->priv->table, action_name); + } +} + +/** + * g_simple_action_group_set_enabled: + * @simple: a #GSimpleActionGroup + * @action_name: the name of an action + * @enabled: if the action should be enabled + * + * Sets an action in the group as being enabled or not. + * + * This is a convenience function, equivalent to calling + * g_simple_action_group_lookup() and using g_action_set_enabled() on + * the result. + * + * If no action named @action_name exists then this function does + * nothing. + * + * Since: 2.26 + **/ +void +g_simple_action_group_set_enabled (GSimpleActionGroup *simple, + const gchar *action_name, + gboolean enabled) +{ + GAction *action; + + g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple)); + + action = g_hash_table_lookup (simple->priv->table, action_name); + + if (action != NULL) + g_action_set_enabled (action, enabled); +} diff --git a/gio/gsimpleactiongroup.h b/gio/gsimpleactiongroup.h new file mode 100644 index 000000000..2637a4756 --- /dev/null +++ b/gio/gsimpleactiongroup.h @@ -0,0 +1,91 @@ +/* + * Copyright © 2010 Codethink Limited + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Ryan Lortie + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_SIMPLE_ACTION_GROUP_H__ +#define __G_SIMPLE_ACTION_GROUP_H__ + +#include "gactiongroup.h" + +G_BEGIN_DECLS + +#define G_TYPE_SIMPLE_ACTION_GROUP (g_simple_action_group_get_type ()) +#define G_SIMPLE_ACTION_GROUP(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_SIMPLE_ACTION_GROUP, GSimpleActionGroup)) +#define G_SIMPLE_ACTION_GROUP_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \ + G_TYPE_SIMPLE_ACTION_GROUP, GSimpleActionGroupClass)) +#define G_IS_SIMPLE_ACTION_GROUP(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + G_TYPE_SIMPLE_ACTION_GROUP)) +#define G_IS_SIMPLE_ACTION_GROUP_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \ + G_TYPE_SIMPLE_ACTION_GROUP)) +#define G_SIMPLE_ACTION_GROUP_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \ + G_TYPE_SIMPLE_ACTION_GROUP, GSimpleActionGroupClass)) + +typedef struct _GSimpleActionGroupPrivate GSimpleActionGroupPrivate; +typedef struct _GSimpleActionGroupClass GSimpleActionGroupClass; + +/** + * GSimpleActionGroup: + * + * The #GSimpleActionGroup structure contains private data and should only be accessed using the provided API. + * + * Since: 2.26 + */ +struct _GSimpleActionGroup +{ + /*< private >*/ + GActionGroup parent_instance; + + GSimpleActionGroupPrivate *priv; +}; + +struct _GSimpleActionGroupClass +{ + /*< private >*/ + GActionGroupClass parent_class; + + /*< private >*/ + gpointer padding[12]; +}; + +GType g_simple_action_group_get_type (void) G_GNUC_CONST; + +GSimpleActionGroup * g_simple_action_group_new (void); + +GAction * g_simple_action_group_lookup (GSimpleActionGroup *simple, + const gchar *action_name); + +void g_simple_action_group_insert (GSimpleActionGroup *simple, + GAction *action); + +void g_simple_action_group_remove (GSimpleActionGroup *simple, + const gchar *action_name); + +void g_simple_action_group_set_enabled (GSimpleActionGroup *simple, + const gchar *action_name, + gboolean enabled); + +G_END_DECLS + +#endif /* __G_SIMPLE_ACTION_GROUP_H__ */ diff --git a/gio/tests/actions.c b/gio/tests/actions.c index 326bb59fe..9d24da084 100644 --- a/gio/tests/actions.c +++ b/gio/tests/actions.c @@ -69,6 +69,33 @@ test_basic (void) g_assert (!a.did_run); } +static void +test_simple_group (void) +{ + GSimpleActionGroup *group; + Activation a = { 0, }; + GAction *action; + + action = g_action_new ("foo", NULL); + g_signal_connect (action, "activate", G_CALLBACK (activate), &a); + g_assert (!a.did_run); + g_action_activate (action, NULL); + g_assert (a.did_run); + a.did_run = FALSE; + + group = g_simple_action_group_new (); + g_simple_action_group_insert (group, action); + g_object_unref (action); + + g_assert (!a.did_run); + g_action_group_activate (G_ACTION_GROUP (group), "foo", NULL); + g_assert (a.did_run); + + a.did_run = FALSE; + g_object_unref (group); + g_assert (!a.did_run); +} + int main (int argc, char **argv) { @@ -76,6 +103,7 @@ main (int argc, char **argv) g_test_init (&argc, &argv, NULL); g_test_add_func ("/actions/basic", test_basic); + g_test_add_func ("/actions/simplegroup", test_simple_group); return g_test_run (); }