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 "gsimpleaction.h"
25
26 #include "gaction.h"
27 #include "glibintl.h"
28
29 /**
30 * GSimpleAction:
31 *
32 * A `GSimpleAction` is the obvious simple implementation of the
33 * [iface@Gio.Action] interface. This is the easiest way to create an action for
34 * purposes of adding it to a [class@Gio.SimpleActionGroup].
35 *
36 * See also [class@Gtk.Action].
37 */
38
39 struct _GSimpleAction
40 {
41 GObject parent_instance;
42
43 gchar *name;
44 GVariantType *parameter_type;
45 gboolean enabled;
46 GVariant *state;
47 GVariant *state_hint;
48 gboolean state_set_already;
49 };
50
51 typedef GObjectClass GSimpleActionClass;
52
53 static void g_simple_action_iface_init (GActionInterface *iface);
54 G_DEFINE_TYPE_WITH_CODE (GSimpleAction, g_simple_action, G_TYPE_OBJECT,
55 G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_simple_action_iface_init))
56
57 enum
58 {
59 PROP_NONE,
60 PROP_NAME,
61 PROP_PARAMETER_TYPE,
62 PROP_ENABLED,
63 PROP_STATE_TYPE,
64 PROP_STATE
65 };
66
67 enum
68 {
69 SIGNAL_CHANGE_STATE,
70 SIGNAL_ACTIVATE,
71 NR_SIGNALS
72 };
73
74 static guint g_simple_action_signals[NR_SIGNALS];
75
76 static const gchar *
77 g_simple_action_get_name (GAction *action)
78 {
79 GSimpleAction *simple = G_SIMPLE_ACTION (action);
80
81 return simple->name;
82 }
83
84 static const GVariantType *
85 g_simple_action_get_parameter_type (GAction *action)
86 {
87 GSimpleAction *simple = G_SIMPLE_ACTION (action);
88
89 return simple->parameter_type;
90 }
91
92 static const GVariantType *
93 g_simple_action_get_state_type (GAction *action)
94 {
95 GSimpleAction *simple = G_SIMPLE_ACTION (action);
96
97 if (simple->state != NULL)
98 return g_variant_get_type (simple->state);
99 else
100 return NULL;
101 }
102
103 static GVariant *
104 g_simple_action_get_state_hint (GAction *action)
105 {
106 GSimpleAction *simple = G_SIMPLE_ACTION (action);
107
108 if (simple->state_hint != NULL)
109 return g_variant_ref (simple->state_hint);
110 else
111 return NULL;
112 }
113
114 static gboolean
115 g_simple_action_get_enabled (GAction *action)
116 {
117 GSimpleAction *simple = G_SIMPLE_ACTION (action);
118
119 return simple->enabled;
120 }
121
122 static void
123 g_simple_action_change_state (GAction *action,
124 GVariant *value)
125 {
126 GSimpleAction *simple = G_SIMPLE_ACTION (action);
127
128 /* If the user connected a signal handler then they are responsible
129 * for handling state changes.
130 */
131 if (g_signal_has_handler_pending (action, g_simple_action_signals[SIGNAL_CHANGE_STATE], 0, TRUE))
132 g_signal_emit (action, g_simple_action_signals[SIGNAL_CHANGE_STATE], 0, value);
133
134 /* If not, then the default behaviour is to just set the state. */
135 else
136 g_simple_action_set_state (simple, value);
137 }
138
139 /**
140 * g_simple_action_set_state:
141 * @simple: a #GSimpleAction
142 * @value: the new #GVariant for the state
143 *
144 * Sets the state of the action.
145 *
146 * This directly updates the 'state' property to the given value.
147 *
148 * This should only be called by the implementor of the action. Users
149 * of the action should not attempt to directly modify the 'state'
150 * property. Instead, they should call g_action_change_state() to
151 * request the change.
152 *
153 * If the @value GVariant is floating, it is consumed.
154 *
155 * Since: 2.30
156 **/
157 void
158 g_simple_action_set_state (GSimpleAction *simple,
159 GVariant *value)
160 {
161 g_return_if_fail (G_IS_SIMPLE_ACTION (simple));
162 g_return_if_fail (value != NULL);
163
164 {
165 const GVariantType *state_type;
166
167 state_type = simple->state ?
168 g_variant_get_type (simple->state) : NULL;
169 g_return_if_fail (state_type != NULL);
170 g_return_if_fail (g_variant_is_of_type (value, state_type));
171 }
172
173 g_variant_ref_sink (value);
174
175 if (!simple->state || !g_variant_equal (simple->state, value))
176 {
177 if (simple->state)
178 g_variant_unref (simple->state);
179
180 simple->state = g_variant_ref (value);
181
182 g_object_notify (G_OBJECT (simple), "state");
183 }
184
185 g_variant_unref (value);
186 }
187
188 static GVariant *
189 g_simple_action_get_state (GAction *action)
190 {
191 GSimpleAction *simple = G_SIMPLE_ACTION (action);
192
193 return simple->state ? g_variant_ref (simple->state) : NULL;
194 }
195
196 static void
197 g_simple_action_activate (GAction *action,
198 GVariant *parameter)
199 {
200 GSimpleAction *simple = G_SIMPLE_ACTION (action);
201
202 g_return_if_fail (simple->parameter_type == NULL ?
203 parameter == NULL :
204 (parameter != NULL &&
205 g_variant_is_of_type (parameter,
206 simple->parameter_type)));
207
208 if (parameter != NULL)
209 g_variant_ref_sink (parameter);
210
211 if (simple->enabled)
212 {
213 /* If the user connected a signal handler then they are responsible
214 * for handling activation.
215 */
216 if (g_signal_has_handler_pending (action, g_simple_action_signals[SIGNAL_ACTIVATE], 0, TRUE))
217 g_signal_emit (action, g_simple_action_signals[SIGNAL_ACTIVATE], 0, parameter);
218
219 /* If not, do some reasonable defaults for stateful actions. */
220 else if (simple->state)
221 {
222 /* If we have no parameter and this is a boolean action, toggle. */
223 if (parameter == NULL && g_variant_is_of_type (simple->state, G_VARIANT_TYPE_BOOLEAN))
224 {
225 gboolean was_enabled = g_variant_get_boolean (simple->state);
226 g_simple_action_change_state (action, g_variant_new_boolean (!was_enabled));
227 }
228
229 /* else, if the parameter and state type are the same, do a change-state */
230 else if (g_variant_is_of_type (simple->state, g_variant_get_type (parameter)))
231 g_simple_action_change_state (action, parameter);
232 }
233 }
234
235 if (parameter != NULL)
236 g_variant_unref (parameter);
237 }
238
239 static void
240 g_simple_action_set_property (GObject *object,
241 guint prop_id,
242 const GValue *value,
243 GParamSpec *pspec)
244 {
245 GSimpleAction *action = G_SIMPLE_ACTION (object);
246
247 switch (prop_id)
248 {
249 case PROP_NAME:
250 action->name = g_strdup (g_value_get_string (value));
251 break;
252
253 case PROP_PARAMETER_TYPE:
254 action->parameter_type = g_value_dup_boxed (value);
255 break;
256
257 case PROP_ENABLED:
258 action->enabled = g_value_get_boolean (value);
259 break;
260
261 case PROP_STATE:
262 /* The first time we see this (during construct) we should just
263 * take the state as it was handed to us.
264 *
265 * After that, we should make sure we go through the same checks
266 * as the C API.
267 */
268 if (!action->state_set_already)
269 {
270 action->state = g_value_dup_variant (value);
271 action->state_set_already = TRUE;
272 }
273 else
274 g_simple_action_set_state (action, g_value_get_variant (value));
275
276 break;
277
278 default:
279 g_assert_not_reached ();
280 }
281 }
282
283 static void
284 g_simple_action_get_property (GObject *object,
285 guint prop_id,
286 GValue *value,
287 GParamSpec *pspec)
288 {
289 GAction *action = G_ACTION (object);
290
291 switch (prop_id)
292 {
293 case PROP_NAME:
294 g_value_set_string (value, g_simple_action_get_name (action));
295 break;
296
297 case PROP_PARAMETER_TYPE:
298 g_value_set_boxed (value, g_simple_action_get_parameter_type (action));
299 break;
300
301 case PROP_ENABLED:
302 g_value_set_boolean (value, g_simple_action_get_enabled (action));
303 break;
304
305 case PROP_STATE_TYPE:
306 g_value_set_boxed (value, g_simple_action_get_state_type (action));
307 break;
308
309 case PROP_STATE:
310 g_value_take_variant (value, g_simple_action_get_state (action));
311 break;
312
313 default:
314 g_assert_not_reached ();
315 }
316 }
317
318 static void
319 g_simple_action_finalize (GObject *object)
320 {
321 GSimpleAction *simple = G_SIMPLE_ACTION (object);
322
323 g_free (simple->name);
324 if (simple->parameter_type)
325 g_variant_type_free (simple->parameter_type);
326 if (simple->state)
327 g_variant_unref (simple->state);
328 if (simple->state_hint)
329 g_variant_unref (simple->state_hint);
330
331 G_OBJECT_CLASS (g_simple_action_parent_class)
332 ->finalize (object);
333 }
334
335 void
336 g_simple_action_init (GSimpleAction *simple)
337 {
338 simple->enabled = TRUE;
339 }
340
341 void
342 g_simple_action_iface_init (GActionInterface *iface)
343 {
344 iface->get_name = g_simple_action_get_name;
345 iface->get_parameter_type = g_simple_action_get_parameter_type;
346 iface->get_state_type = g_simple_action_get_state_type;
347 iface->get_state_hint = g_simple_action_get_state_hint;
348 iface->get_enabled = g_simple_action_get_enabled;
349 iface->get_state = g_simple_action_get_state;
350 iface->change_state = g_simple_action_change_state;
351 iface->activate = g_simple_action_activate;
352 }
353
354 void
355 g_simple_action_class_init (GSimpleActionClass *class)
356 {
357 GObjectClass *object_class = G_OBJECT_CLASS (class);
358
359 object_class->set_property = g_simple_action_set_property;
360 object_class->get_property = g_simple_action_get_property;
361 object_class->finalize = g_simple_action_finalize;
362
363 /**
364 * GSimpleAction::activate:
365 * @simple: the #GSimpleAction
366 * @parameter: (nullable): the parameter to the activation, or %NULL if it has
367 * no parameter
368 *
369 * Indicates that the action was just activated.
370 *
371 * @parameter will always be of the expected type, i.e. the parameter type
372 * specified when the action was created. If an incorrect type is given when
373 * activating the action, this signal is not emitted.
374 *
375 * Since GLib 2.40, if no handler is connected to this signal then the
376 * default behaviour for boolean-stated actions with a %NULL parameter
377 * type is to toggle them via the #GSimpleAction::change-state signal.
378 * For stateful actions where the state type is equal to the parameter
379 * type, the default is to forward them directly to
380 * #GSimpleAction::change-state. This should allow almost all users
381 * of #GSimpleAction to connect only one handler or the other.
382 *
383 * Since: 2.28
384 */
385 g_simple_action_signals[SIGNAL_ACTIVATE] =
386 g_signal_new (I_("activate"),
387 G_TYPE_SIMPLE_ACTION,
388 G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
389 0, NULL, NULL,
390 NULL,
391 G_TYPE_NONE, 1,
392 G_TYPE_VARIANT);
393
394 /**
395 * GSimpleAction::change-state:
396 * @simple: the #GSimpleAction
397 * @value: (nullable): the requested value for the state
398 *
399 * Indicates that the action just received a request to change its
400 * state.
401 *
402 * @value will always be of the correct state type, i.e. the type of the
403 * initial state passed to g_simple_action_new_stateful(). If an incorrect
404 * type is given when requesting to change the state, this signal is not
405 * emitted.
406 *
407 * If no handler is connected to this signal then the default
408 * behaviour is to call g_simple_action_set_state() to set the state
409 * to the requested value. If you connect a signal handler then no
410 * default action is taken. If the state should change then you must
411 * call g_simple_action_set_state() from the handler.
412 *
413 * An example of a 'change-state' handler:
414 * |[<!-- language="C" -->
415 * static void
416 * change_volume_state (GSimpleAction *action,
417 * GVariant *value,
418 * gpointer user_data)
419 * {
420 * gint requested;
421 *
422 * requested = g_variant_get_int32 (value);
423 *
424 * // Volume only goes from 0 to 10
425 * if (0 <= requested && requested <= 10)
426 * g_simple_action_set_state (action, value);
427 * }
428 * ]|
429 *
430 * The handler need not set the state to the requested value.
431 * It could set it to any value at all, or take some other action.
432 *
433 * Since: 2.30
434 */
435 g_simple_action_signals[SIGNAL_CHANGE_STATE] =
436 g_signal_new (I_("change-state"),
437 G_TYPE_SIMPLE_ACTION,
438 G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
439 0, NULL, NULL,
440 NULL,
441 G_TYPE_NONE, 1,
442 G_TYPE_VARIANT);
443
444 /**
445 * GSimpleAction:name:
446 *
447 * The name of the action. This is mostly meaningful for identifying
448 * the action once it has been added to a #GSimpleActionGroup.
449 *
450 * Since: 2.28
451 **/
452 g_object_class_install_property (object_class, PROP_NAME,
453 g_param_spec_string ("name", NULL, NULL,
454 NULL,
455 G_PARAM_READWRITE |
456 G_PARAM_CONSTRUCT_ONLY |
457 G_PARAM_STATIC_STRINGS));
458
459 /**
460 * GSimpleAction:parameter-type:
461 *
462 * The type of the parameter that must be given when activating the
463 * action.
464 *
465 * Since: 2.28
466 **/
467 g_object_class_install_property (object_class, PROP_PARAMETER_TYPE,
468 g_param_spec_boxed ("parameter-type", NULL, NULL,
469 G_TYPE_VARIANT_TYPE,
470 G_PARAM_READWRITE |
471 G_PARAM_CONSTRUCT_ONLY |
472 G_PARAM_STATIC_STRINGS));
473
474 /**
475 * GSimpleAction:enabled:
476 *
477 * If @action is currently enabled.
478 *
479 * If the action is disabled then calls to g_action_activate() and
480 * g_action_change_state() have no effect.
481 *
482 * Since: 2.28
483 **/
484 g_object_class_install_property (object_class, PROP_ENABLED,
485 g_param_spec_boolean ("enabled", NULL, NULL,
486 TRUE,
487 G_PARAM_READWRITE |
488 G_PARAM_STATIC_STRINGS));
489
490 /**
491 * GSimpleAction:state-type:
492 *
493 * The #GVariantType of the state that the action has, or %NULL if the
494 * action is stateless.
495 *
496 * Since: 2.28
497 **/
498 g_object_class_install_property (object_class, PROP_STATE_TYPE,
499 g_param_spec_boxed ("state-type", NULL, NULL,
500 G_TYPE_VARIANT_TYPE,
501 G_PARAM_READABLE |
502 G_PARAM_STATIC_STRINGS));
503
504 /**
505 * GSimpleAction:state:
506 *
507 * The state of the action, or %NULL if the action is stateless.
508 *
509 * Since: 2.28
510 **/
511 g_object_class_install_property (object_class, PROP_STATE,
512 g_param_spec_variant ("state", NULL, NULL,
513 G_VARIANT_TYPE_ANY,
514 NULL,
515 G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
516 G_PARAM_STATIC_STRINGS));
517 }
518
519 /**
520 * g_simple_action_set_enabled:
521 * @simple: a #GSimpleAction
522 * @enabled: whether the action is enabled
523 *
524 * Sets the action as enabled or not.
525 *
526 * An action must be enabled in order to be activated or in order to
527 * have its state changed from outside callers.
528 *
529 * This should only be called by the implementor of the action. Users
530 * of the action should not attempt to modify its enabled flag.
531 *
532 * Since: 2.28
533 **/
534 void
535 g_simple_action_set_enabled (GSimpleAction *simple,
536 gboolean enabled)
537 {
538 g_return_if_fail (G_IS_SIMPLE_ACTION (simple));
539
540 enabled = !!enabled;
541
542 if (simple->enabled != enabled)
543 {
544 simple->enabled = enabled;
545 g_object_notify (G_OBJECT (simple), "enabled");
546 }
547 }
548
549 /**
550 * g_simple_action_set_state_hint:
551 * @simple: a #GSimpleAction
552 * @state_hint: (nullable): a #GVariant representing the state hint
553 *
554 * Sets the state hint for the action.
555 *
556 * See g_action_get_state_hint() for more information about
557 * action state hints.
558 *
559 * Since: 2.44
560 **/
561 void
562 g_simple_action_set_state_hint (GSimpleAction *simple,
563 GVariant *state_hint)
564 {
565 g_return_if_fail (G_IS_SIMPLE_ACTION (simple));
566
567 if (simple->state_hint != NULL)
568 {
569 g_variant_unref (simple->state_hint);
570 simple->state_hint = NULL;
571 }
572
573 if (state_hint != NULL)
574 simple->state_hint = g_variant_ref (state_hint);
575 }
576
577 /**
578 * g_simple_action_new:
579 * @name: the name of the action
580 * @parameter_type: (nullable): the type of parameter that will be passed to
581 * handlers for the #GSimpleAction::activate signal, or %NULL for no parameter
582 *
583 * Creates a new action.
584 *
585 * The created action is stateless. See g_simple_action_new_stateful() to create
586 * an action that has state.
587 *
588 * Returns: a new #GSimpleAction
589 *
590 * Since: 2.28
591 **/
592 GSimpleAction *
593 g_simple_action_new (const gchar *name,
594 const GVariantType *parameter_type)
595 {
596 g_return_val_if_fail (name != NULL, NULL);
597
598 return g_object_new (G_TYPE_SIMPLE_ACTION,
599 "name", name,
600 "parameter-type", parameter_type,
601 NULL);
602 }
603
604 /**
605 * g_simple_action_new_stateful:
606 * @name: the name of the action
607 * @parameter_type: (nullable): the type of the parameter that will be passed to
608 * handlers for the #GSimpleAction::activate signal, or %NULL for no parameter
609 * @state: the initial state of the action
610 *
611 * Creates a new stateful action.
612 *
613 * All future state values must have the same #GVariantType as the initial
614 * @state.
615 *
616 * If the @state #GVariant is floating, it is consumed.
617 *
618 * Returns: a new #GSimpleAction
619 *
620 * Since: 2.28
621 **/
622 GSimpleAction *
623 g_simple_action_new_stateful (const gchar *name,
624 const GVariantType *parameter_type,
625 GVariant *state)
626 {
627 return g_object_new (G_TYPE_SIMPLE_ACTION,
628 "name", name,
629 "parameter-type", parameter_type,
630 "state", state,
631 NULL);
632 }