Test runtime dir getter
[platform/upstream/glib.git] / gio / gsimpleactiongroup.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 "gsimpleactiongroup.h"
23 #include "gaction.h"
24
25 /**
26  * SECTION:gsimpleactiongroup
27  * @title: GSimpleActionGroup
28  * @short_description: A simple GActionGroup implementation
29  *
30  * #GSimpleActionGroup is a hash table filled with #GAction objects,
31  * implementing the #GActionGroup interface.
32  **/
33
34 struct _GSimpleActionGroupPrivate
35 {
36   GHashTable *table;  /* string -> GAction */
37 };
38
39 static void g_simple_action_group_iface_init (GActionGroupInterface *);
40 G_DEFINE_TYPE_WITH_CODE (GSimpleActionGroup,
41   g_simple_action_group, G_TYPE_OBJECT,
42   G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
43     g_simple_action_group_iface_init))
44
45 static gchar **
46 g_simple_action_group_list_actions (GActionGroup *group)
47 {
48   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
49   GHashTableIter iter;
50   gint n, i = 0;
51   gchar **keys;
52   gpointer key;
53
54   n = g_hash_table_size (simple->priv->table);
55   keys = g_new (gchar *, n + 1);
56
57   g_hash_table_iter_init (&iter, simple->priv->table);
58   while (g_hash_table_iter_next (&iter, &key, NULL))
59     keys[i++] = g_strdup (key);
60   g_assert_cmpint (i, ==, n);
61   keys[n] = NULL;
62
63   return keys;
64 }
65
66 static gboolean
67 g_simple_action_group_has_action (GActionGroup *group,
68                                   const gchar  *action_name)
69 {
70   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
71
72   return g_hash_table_lookup (simple->priv->table, action_name) != NULL;
73 }
74
75 static const GVariantType *
76 g_simple_action_group_get_parameter_type (GActionGroup *group,
77                                           const gchar  *action_name)
78 {
79   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
80   GAction *action;
81
82   action = g_hash_table_lookup (simple->priv->table, action_name);
83
84   if (action == NULL)
85     return NULL;
86
87   return g_action_get_parameter_type (action);
88 }
89
90 static const GVariantType *
91 g_simple_action_group_get_state_type (GActionGroup *group,
92                                       const gchar  *action_name)
93 {
94   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
95   GAction *action;
96
97   action = g_hash_table_lookup (simple->priv->table, action_name);
98
99   if (action == NULL)
100     return NULL;
101
102   return g_action_get_state_type (action);
103 }
104
105 static GVariant *
106 g_simple_action_group_get_state_hint (GActionGroup *group,
107                                        const gchar  *action_name)
108 {
109   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
110   GAction *action;
111
112   action = g_hash_table_lookup (simple->priv->table, action_name);
113
114   if (action == NULL)
115     return NULL;
116
117   return g_action_get_state_hint (action);
118 }
119
120 static gboolean
121 g_simple_action_group_get_enabled (GActionGroup *group,
122                                    const gchar  *action_name)
123 {
124   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
125   GAction *action;
126
127   action = g_hash_table_lookup (simple->priv->table, action_name);
128
129   if (action == NULL)
130     return FALSE;
131
132   return g_action_get_enabled (action);
133 }
134
135 static GVariant *
136 g_simple_action_group_get_state (GActionGroup *group,
137                                  const gchar  *action_name)
138 {
139   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
140   GAction *action;
141
142   action = g_hash_table_lookup (simple->priv->table, action_name);
143
144   if (action == NULL)
145     return NULL;
146
147   return g_action_get_state (action);
148 }
149
150 static void
151 g_simple_action_group_set_state (GActionGroup *group,
152                                  const gchar  *action_name,
153                                  GVariant     *value)
154 {
155   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
156   GAction *action;
157
158   action = g_hash_table_lookup (simple->priv->table, action_name);
159
160   if (action == NULL)
161     return;
162
163   g_action_set_state (action, value);
164 }
165
166 static void
167 g_simple_action_group_activate (GActionGroup *group,
168                                 const gchar  *action_name,
169                                 GVariant     *parameter)
170 {
171   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group);
172   GAction *action;
173
174   action = g_hash_table_lookup (simple->priv->table, action_name);
175
176   if (action == NULL)
177     return;
178
179   g_action_activate (action, parameter);
180 }
181
182 static void
183 action_enabled_notify (GAction     *action,
184                        GParamSpec  *pspec,
185                        gpointer     user_data)
186 {
187   g_action_group_action_enabled_changed (user_data,
188                                          g_action_get_name (action),
189                                          g_action_get_enabled (action));
190 }
191
192 static void
193 action_state_notify (GAction    *action,
194                      GParamSpec *pspec,
195                      gpointer    user_data)
196 {
197   GVariant *value;
198
199   value = g_action_get_state (action);
200   g_action_group_action_state_changed (user_data,
201                                        g_action_get_name (action),
202                                        value);
203   g_variant_unref (value);
204 }
205
206 static void
207 g_simple_action_group_disconnect (gpointer key,
208                                   gpointer value,
209                                   gpointer user_data)
210 {
211   g_signal_handlers_disconnect_by_func (value, action_enabled_notify,
212                                         user_data);
213   g_signal_handlers_disconnect_by_func (value, action_state_notify,
214                                         user_data);
215 }
216
217 static void
218 g_simple_action_group_finalize (GObject *object)
219 {
220   GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (object);
221
222   g_hash_table_foreach (simple->priv->table,
223                         g_simple_action_group_disconnect,
224                         simple);
225   g_hash_table_unref (simple->priv->table);
226
227   G_OBJECT_CLASS (g_simple_action_group_parent_class)
228     ->finalize (object);
229 }
230
231 static void
232 g_simple_action_group_init (GSimpleActionGroup *simple)
233 {
234   simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (simple,
235                                               G_TYPE_SIMPLE_ACTION_GROUP,
236                                               GSimpleActionGroupPrivate);
237   simple->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
238                                                g_free, g_object_unref);
239 }
240
241 static void
242 g_simple_action_group_class_init (GSimpleActionGroupClass *class)
243 {
244   GObjectClass *object_class = G_OBJECT_CLASS (class);
245
246   object_class->finalize = g_simple_action_group_finalize;
247
248   g_type_class_add_private (class, sizeof (GSimpleActionGroupPrivate));
249 }
250
251 static void
252 g_simple_action_group_iface_init (GActionGroupInterface *iface)
253 {
254   iface->list_actions = g_simple_action_group_list_actions;
255   iface->has_action = g_simple_action_group_has_action;
256   iface->get_action_parameter_type = g_simple_action_group_get_parameter_type;
257   iface->get_action_state_type = g_simple_action_group_get_state_type;
258   iface->get_action_state_hint = g_simple_action_group_get_state_hint;
259   iface->get_action_enabled = g_simple_action_group_get_enabled;
260   iface->get_action_state = g_simple_action_group_get_state;
261   iface->change_action_state = g_simple_action_group_set_state;
262   iface->activate_action = g_simple_action_group_activate;
263 }
264
265 /**
266  * g_simple_action_group_new:
267  *
268  * Creates a new, empty, #GSimpleActionGroup.
269  *
270  * Returns: a new #GSimpleActionGroup
271  *
272  * Since: 2.28
273  **/
274 GSimpleActionGroup *
275 g_simple_action_group_new (void)
276 {
277   return g_object_new (G_TYPE_SIMPLE_ACTION_GROUP, NULL);
278 }
279
280 /**
281  * g_simple_action_group_lookup:
282  * @simple: a #GSimpleActionGroup
283  * @action_name: the name of an action
284  *
285  * Looks up the action with the name @action_name in the group.
286  *
287  * If no such action exists, returns %NULL.
288  *
289  * Returns: (transfer none): a #GAction, or %NULL
290  *
291  * Since: 2.28
292  **/
293 GAction *
294 g_simple_action_group_lookup (GSimpleActionGroup *simple,
295                               const gchar        *action_name)
296 {
297   g_return_val_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple), NULL);
298
299   return g_hash_table_lookup (simple->priv->table, action_name);
300 }
301
302 /**
303  * g_simple_action_group_insert:
304  * @simple: a #GSimpleActionGroup
305  * @action: a #GAction
306  *
307  * Adds an action to the action group.
308  *
309  * If the action group already contains an action with the same name as
310  * @action then the old action is dropped from the group.
311  *
312  * The action group takes its own reference on @action.
313  *
314  * Since: 2.28
315  **/
316 void
317 g_simple_action_group_insert (GSimpleActionGroup *simple,
318                               GAction            *action)
319 {
320   const gchar *action_name;
321   GAction *old_action;
322
323   g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
324   g_return_if_fail (G_IS_ACTION (action));
325
326   action_name = g_action_get_name (action);
327   old_action = g_hash_table_lookup (simple->priv->table, action_name);
328
329   if (old_action != action)
330     {
331       if (old_action != NULL)
332         {
333           g_action_group_action_removed (G_ACTION_GROUP (simple),
334                                          action_name);
335           g_simple_action_group_disconnect (NULL, old_action, simple);
336         }
337
338       g_signal_connect (action, "notify::enabled",
339                         G_CALLBACK (action_enabled_notify), simple);
340
341       if (g_action_get_state_type (action) != NULL)
342         g_signal_connect (action, "notify::state",
343                           G_CALLBACK (action_state_notify), simple);
344
345       g_hash_table_insert (simple->priv->table,
346                            g_strdup (action_name),
347                            g_object_ref (action));
348
349       g_action_group_action_added (G_ACTION_GROUP (simple), action_name);
350     }
351 }
352
353 /**
354  * g_simple_action_group_remove:
355  * @simple: a #GSimpleActionGroup
356  * @action_name: the name of the action
357  *
358  * Removes the named action from the action group.
359  *
360  * If no action of this name is in the group then nothing happens.
361  *
362  * Since: 2.28
363  **/
364 void
365 g_simple_action_group_remove (GSimpleActionGroup *simple,
366                               const gchar        *action_name)
367 {
368   GAction *action;
369
370   g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple));
371
372   action = g_hash_table_lookup (simple->priv->table, action_name);
373
374   if (action != NULL)
375     {
376       g_action_group_action_removed (G_ACTION_GROUP (simple), action_name);
377       g_simple_action_group_disconnect (NULL, action, simple);
378       g_hash_table_remove (simple->priv->table, action_name);
379     }
380 }