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