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