/src/glib/gio/gsimpleactiongroup.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2010 Codethink Limited |
3 | | * |
4 | | * This library is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Lesser General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2.1 of the License, or (at 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, see <http://www.gnu.org/licenses/>. |
16 | | * |
17 | | * Authors: Ryan Lortie <desrt@desrt.ca> |
18 | | */ |
19 | | |
20 | | #include "config.h" |
21 | | |
22 | | #include "gsimpleactiongroup.h" |
23 | | |
24 | | #include "gsimpleaction.h" |
25 | | #include "gactionmap.h" |
26 | | #include "gaction.h" |
27 | | |
28 | | /** |
29 | | * SECTION:gsimpleactiongroup |
30 | | * @title: GSimpleActionGroup |
31 | | * @short_description: A simple GActionGroup implementation |
32 | | * @include: gio/gio.h |
33 | | * |
34 | | * #GSimpleActionGroup is a hash table filled with #GAction objects, |
35 | | * implementing the #GActionGroup and #GActionMap interfaces. |
36 | | **/ |
37 | | |
38 | | struct _GSimpleActionGroupPrivate |
39 | | { |
40 | | GHashTable *table; /* string -> GAction */ |
41 | | }; |
42 | | |
43 | | static void g_simple_action_group_iface_init (GActionGroupInterface *); |
44 | | static void g_simple_action_group_map_iface_init (GActionMapInterface *); |
45 | | G_DEFINE_TYPE_WITH_CODE (GSimpleActionGroup, |
46 | | g_simple_action_group, G_TYPE_OBJECT, |
47 | | G_ADD_PRIVATE (GSimpleActionGroup) |
48 | | G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, |
49 | | g_simple_action_group_iface_init); |
50 | | G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP, |
51 | | g_simple_action_group_map_iface_init)) |
52 | | |
53 | | static gchar ** |
54 | | g_simple_action_group_list_actions (GActionGroup *group) |
55 | 0 | { |
56 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); |
57 | 0 | GHashTableIter iter; |
58 | 0 | gint n, i = 0; |
59 | 0 | gchar **keys; |
60 | 0 | gpointer key; |
61 | |
|
62 | 0 | n = g_hash_table_size (simple->priv->table); |
63 | 0 | keys = g_new (gchar *, n + 1); |
64 | |
|
65 | 0 | g_hash_table_iter_init (&iter, simple->priv->table); |
66 | 0 | while (g_hash_table_iter_next (&iter, &key, NULL)) |
67 | 0 | keys[i++] = g_strdup (key); |
68 | 0 | g_assert_cmpint (i, ==, n); |
69 | 0 | keys[n] = NULL; |
70 | |
|
71 | 0 | return keys; |
72 | 0 | } |
73 | | |
74 | | static gboolean |
75 | | g_simple_action_group_query_action (GActionGroup *group, |
76 | | const gchar *action_name, |
77 | | gboolean *enabled, |
78 | | const GVariantType **parameter_type, |
79 | | const GVariantType **state_type, |
80 | | GVariant **state_hint, |
81 | | GVariant **state) |
82 | 0 | { |
83 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); |
84 | 0 | GAction *action; |
85 | |
|
86 | 0 | action = g_hash_table_lookup (simple->priv->table, action_name); |
87 | |
|
88 | 0 | if (action == NULL) |
89 | 0 | return FALSE; |
90 | | |
91 | 0 | if (enabled) |
92 | 0 | *enabled = g_action_get_enabled (action); |
93 | |
|
94 | 0 | if (parameter_type) |
95 | 0 | *parameter_type = g_action_get_parameter_type (action); |
96 | |
|
97 | 0 | if (state_type) |
98 | 0 | *state_type = g_action_get_state_type (action); |
99 | |
|
100 | 0 | if (state_hint) |
101 | 0 | *state_hint = g_action_get_state_hint (action); |
102 | |
|
103 | 0 | if (state) |
104 | 0 | *state = g_action_get_state (action); |
105 | |
|
106 | 0 | return TRUE; |
107 | 0 | } |
108 | | |
109 | | static void |
110 | | g_simple_action_group_change_state (GActionGroup *group, |
111 | | const gchar *action_name, |
112 | | GVariant *value) |
113 | 0 | { |
114 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); |
115 | 0 | GAction *action; |
116 | |
|
117 | 0 | action = g_hash_table_lookup (simple->priv->table, action_name); |
118 | |
|
119 | 0 | if (action == NULL) |
120 | 0 | return; |
121 | | |
122 | 0 | g_action_change_state (action, value); |
123 | 0 | } |
124 | | |
125 | | static void |
126 | | g_simple_action_group_activate (GActionGroup *group, |
127 | | const gchar *action_name, |
128 | | GVariant *parameter) |
129 | 0 | { |
130 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (group); |
131 | 0 | GAction *action; |
132 | |
|
133 | 0 | action = g_hash_table_lookup (simple->priv->table, action_name); |
134 | |
|
135 | 0 | if (action == NULL) |
136 | 0 | return; |
137 | | |
138 | 0 | g_action_activate (action, parameter); |
139 | 0 | } |
140 | | |
141 | | static void |
142 | | action_enabled_notify (GAction *action, |
143 | | GParamSpec *pspec, |
144 | | gpointer user_data) |
145 | 0 | { |
146 | 0 | g_action_group_action_enabled_changed (user_data, |
147 | 0 | g_action_get_name (action), |
148 | 0 | g_action_get_enabled (action)); |
149 | 0 | } |
150 | | |
151 | | static void |
152 | | action_state_notify (GAction *action, |
153 | | GParamSpec *pspec, |
154 | | gpointer user_data) |
155 | 0 | { |
156 | 0 | GVariant *value; |
157 | |
|
158 | 0 | value = g_action_get_state (action); |
159 | 0 | g_action_group_action_state_changed (user_data, |
160 | 0 | g_action_get_name (action), |
161 | 0 | value); |
162 | 0 | g_variant_unref (value); |
163 | 0 | } |
164 | | |
165 | | static void |
166 | | g_simple_action_group_disconnect (gpointer key, |
167 | | gpointer value, |
168 | | gpointer user_data) |
169 | 0 | { |
170 | 0 | g_signal_handlers_disconnect_by_func (value, action_enabled_notify, |
171 | 0 | user_data); |
172 | 0 | g_signal_handlers_disconnect_by_func (value, action_state_notify, |
173 | 0 | user_data); |
174 | 0 | } |
175 | | |
176 | | static GAction * |
177 | | g_simple_action_group_lookup_action (GActionMap *action_map, |
178 | | const gchar *action_name) |
179 | 0 | { |
180 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (action_map); |
181 | |
|
182 | 0 | return g_hash_table_lookup (simple->priv->table, action_name); |
183 | 0 | } |
184 | | |
185 | | static void |
186 | | g_simple_action_group_add_action (GActionMap *action_map, |
187 | | GAction *action) |
188 | 0 | { |
189 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (action_map); |
190 | 0 | const gchar *action_name; |
191 | 0 | GAction *old_action; |
192 | |
|
193 | 0 | action_name = g_action_get_name (action); |
194 | 0 | if (action_name == NULL) |
195 | 0 | { |
196 | 0 | g_critical ("The supplied action has no name. You must set the " |
197 | 0 | "GAction:name property when creating an action."); |
198 | 0 | return; |
199 | 0 | } |
200 | | |
201 | 0 | old_action = g_hash_table_lookup (simple->priv->table, action_name); |
202 | |
|
203 | 0 | if (old_action != action) |
204 | 0 | { |
205 | 0 | if (old_action != NULL) |
206 | 0 | { |
207 | 0 | g_action_group_action_removed (G_ACTION_GROUP (simple), |
208 | 0 | action_name); |
209 | 0 | g_simple_action_group_disconnect (NULL, old_action, simple); |
210 | 0 | } |
211 | |
|
212 | 0 | g_signal_connect (action, "notify::enabled", |
213 | 0 | G_CALLBACK (action_enabled_notify), simple); |
214 | |
|
215 | 0 | if (g_action_get_state_type (action) != NULL) |
216 | 0 | g_signal_connect (action, "notify::state", |
217 | 0 | G_CALLBACK (action_state_notify), simple); |
218 | |
|
219 | 0 | g_hash_table_insert (simple->priv->table, |
220 | 0 | g_strdup (action_name), |
221 | 0 | g_object_ref (action)); |
222 | |
|
223 | 0 | g_action_group_action_added (G_ACTION_GROUP (simple), action_name); |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | | static void |
228 | | g_simple_action_group_remove_action (GActionMap *action_map, |
229 | | const gchar *action_name) |
230 | 0 | { |
231 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (action_map); |
232 | 0 | GAction *action; |
233 | |
|
234 | 0 | action = g_hash_table_lookup (simple->priv->table, action_name); |
235 | |
|
236 | 0 | if (action != NULL) |
237 | 0 | { |
238 | 0 | g_action_group_action_removed (G_ACTION_GROUP (simple), action_name); |
239 | 0 | g_simple_action_group_disconnect (NULL, action, simple); |
240 | 0 | g_hash_table_remove (simple->priv->table, action_name); |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | static void |
245 | | g_simple_action_group_finalize (GObject *object) |
246 | 0 | { |
247 | 0 | GSimpleActionGroup *simple = G_SIMPLE_ACTION_GROUP (object); |
248 | |
|
249 | 0 | g_hash_table_foreach (simple->priv->table, |
250 | 0 | g_simple_action_group_disconnect, |
251 | 0 | simple); |
252 | 0 | g_hash_table_unref (simple->priv->table); |
253 | |
|
254 | 0 | G_OBJECT_CLASS (g_simple_action_group_parent_class) |
255 | 0 | ->finalize (object); |
256 | 0 | } |
257 | | |
258 | | static void |
259 | | g_simple_action_group_init (GSimpleActionGroup *simple) |
260 | 0 | { |
261 | 0 | simple->priv = g_simple_action_group_get_instance_private (simple); |
262 | 0 | simple->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal, |
263 | 0 | g_free, g_object_unref); |
264 | 0 | } |
265 | | |
266 | | static void |
267 | | g_simple_action_group_class_init (GSimpleActionGroupClass *class) |
268 | 0 | { |
269 | 0 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
270 | |
|
271 | 0 | object_class->finalize = g_simple_action_group_finalize; |
272 | 0 | } |
273 | | |
274 | | static void |
275 | | g_simple_action_group_iface_init (GActionGroupInterface *iface) |
276 | 0 | { |
277 | 0 | iface->list_actions = g_simple_action_group_list_actions; |
278 | 0 | iface->query_action = g_simple_action_group_query_action; |
279 | 0 | iface->change_action_state = g_simple_action_group_change_state; |
280 | 0 | iface->activate_action = g_simple_action_group_activate; |
281 | 0 | } |
282 | | |
283 | | static void |
284 | | g_simple_action_group_map_iface_init (GActionMapInterface *iface) |
285 | 0 | { |
286 | 0 | iface->add_action = g_simple_action_group_add_action; |
287 | 0 | iface->remove_action = g_simple_action_group_remove_action; |
288 | 0 | iface->lookup_action = g_simple_action_group_lookup_action; |
289 | 0 | } |
290 | | |
291 | | /** |
292 | | * g_simple_action_group_new: |
293 | | * |
294 | | * Creates a new, empty, #GSimpleActionGroup. |
295 | | * |
296 | | * Returns: a new #GSimpleActionGroup |
297 | | * |
298 | | * Since: 2.28 |
299 | | **/ |
300 | | GSimpleActionGroup * |
301 | | g_simple_action_group_new (void) |
302 | 0 | { |
303 | 0 | return g_object_new (G_TYPE_SIMPLE_ACTION_GROUP, NULL); |
304 | 0 | } |
305 | | |
306 | | /** |
307 | | * g_simple_action_group_lookup: |
308 | | * @simple: a #GSimpleActionGroup |
309 | | * @action_name: the name of an action |
310 | | * |
311 | | * Looks up the action with the name @action_name in the group. |
312 | | * |
313 | | * If no such action exists, returns %NULL. |
314 | | * |
315 | | * Returns: (transfer none): a #GAction, or %NULL |
316 | | * |
317 | | * Since: 2.28 |
318 | | * |
319 | | * Deprecated: 2.38: Use g_action_map_lookup_action() |
320 | | */ |
321 | | GAction * |
322 | | g_simple_action_group_lookup (GSimpleActionGroup *simple, |
323 | | const gchar *action_name) |
324 | 0 | { |
325 | 0 | g_return_val_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple), NULL); |
326 | | |
327 | 0 | return g_action_map_lookup_action (G_ACTION_MAP (simple), action_name); |
328 | 0 | } |
329 | | |
330 | | /** |
331 | | * g_simple_action_group_insert: |
332 | | * @simple: a #GSimpleActionGroup |
333 | | * @action: a #GAction |
334 | | * |
335 | | * Adds an action to the action group. |
336 | | * |
337 | | * If the action group already contains an action with the same name as |
338 | | * @action then the old action is dropped from the group. |
339 | | * |
340 | | * The action group takes its own reference on @action. |
341 | | * |
342 | | * Since: 2.28 |
343 | | * |
344 | | * Deprecated: 2.38: Use g_action_map_add_action() |
345 | | **/ |
346 | | void |
347 | | g_simple_action_group_insert (GSimpleActionGroup *simple, |
348 | | GAction *action) |
349 | 0 | { |
350 | 0 | g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple)); |
351 | | |
352 | 0 | g_action_map_add_action (G_ACTION_MAP (simple), action); |
353 | 0 | } |
354 | | |
355 | | /** |
356 | | * g_simple_action_group_remove: |
357 | | * @simple: a #GSimpleActionGroup |
358 | | * @action_name: the name of the action |
359 | | * |
360 | | * Removes the named action from the action group. |
361 | | * |
362 | | * If no action of this name is in the group then nothing happens. |
363 | | * |
364 | | * Since: 2.28 |
365 | | * |
366 | | * Deprecated: 2.38: Use g_action_map_remove_action() |
367 | | **/ |
368 | | void |
369 | | g_simple_action_group_remove (GSimpleActionGroup *simple, |
370 | | const gchar *action_name) |
371 | 0 | { |
372 | 0 | g_return_if_fail (G_IS_SIMPLE_ACTION_GROUP (simple)); |
373 | | |
374 | 0 | g_action_map_remove_action (G_ACTION_MAP (simple), action_name); |
375 | 0 | } |
376 | | |
377 | | |
378 | | /** |
379 | | * g_simple_action_group_add_entries: |
380 | | * @simple: a #GSimpleActionGroup |
381 | | * @entries: (array length=n_entries): a pointer to the first item in |
382 | | * an array of #GActionEntry structs |
383 | | * @n_entries: the length of @entries, or -1 |
384 | | * @user_data: the user data for signal connections |
385 | | * |
386 | | * A convenience function for creating multiple #GSimpleAction instances |
387 | | * and adding them to the action group. |
388 | | * |
389 | | * Since: 2.30 |
390 | | * |
391 | | * Deprecated: 2.38: Use g_action_map_add_action_entries() |
392 | | **/ |
393 | | void |
394 | | g_simple_action_group_add_entries (GSimpleActionGroup *simple, |
395 | | const GActionEntry *entries, |
396 | | gint n_entries, |
397 | | gpointer user_data) |
398 | 0 | { |
399 | 0 | g_action_map_add_action_entries (G_ACTION_MAP (simple), entries, n_entries, user_data); |
400 | 0 | } |