GSimpleAction: add default activate handler
authorRyan Lortie <desrt@desrt.ca>
Sat, 18 Jan 2014 18:02:47 +0000 (13:02 -0500)
committerRyan Lortie <desrt@desrt.ca>
Sat, 18 Jan 2014 19:19:37 +0000 (14:19 -0500)
If the action is stateful and the user doesn't have their own activate handler
then do some reasonable things for ourselves.

After a lot of experience using stateful GSimpleAction it turns out that
people almost always end up using it in the same ways:

A boolean-typed stateful action with no parameter is most likely going
to want to be toggled.  Any other type of action that has the parameter
type equal to the state type probably intends for activation to
represent a request to change the state.

This patch implements those two cases.  This will let people stop
writing their own trivial handlers over and over.

https://bugzilla.gnome.org/show_bug.cgi?id=722503

gio/gsimpleaction.c

index 5ee9806..819f50b 100644 (file)
@@ -205,7 +205,28 @@ g_simple_action_activate (GAction  *action,
     g_variant_ref_sink (parameter);
 
   if (simple->enabled)
-    g_signal_emit (simple, g_simple_action_signals[SIGNAL_ACTIVATE], 0, parameter);
+    {
+      /* If the user connected a signal handler then they are responsible
+       * for handling activation.
+       */
+      if (g_signal_has_handler_pending (action, g_simple_action_signals[SIGNAL_ACTIVATE], 0, TRUE))
+        g_signal_emit (action, g_simple_action_signals[SIGNAL_CHANGE_STATE], 0, parameter);
+
+      /* If not, do some reasonable defaults for stateful actions. */
+      else if (simple->state)
+        {
+          /* If we have no parameter and this is a boolean action, toggle. */
+          if (parameter == NULL && g_variant_is_of_type (simple->state, G_VARIANT_TYPE_BOOLEAN))
+            {
+              gboolean was_enabled = g_variant_get_boolean (simple->state);
+              g_simple_action_change_state (action, g_variant_new_boolean (!was_enabled));
+            }
+
+          /* else, if the parameter and state type are the same, do a change-state */
+          else if (g_variant_is_of_type (simple->state, g_variant_get_type (parameter)))
+            g_simple_action_change_state (action, parameter);
+        }
+    }
 
   if (parameter != NULL)
     g_variant_unref (parameter);
@@ -343,6 +364,14 @@ g_simple_action_class_init (GSimpleActionClass *class)
    * @parameter will always be of the expected type.  In the event that
    * an incorrect type was given, no signal will be emitted.
    *
+   * Since GLib 2.40, if no handler is connected to this signal then the
+   * default behaviour for boolean-stated actions with a %NULL parameter
+   * type is to toggle them via the #GSimpleAction::change-state signal.
+   * For stateful actions where the state type is equal to the parameter
+   * type, the default is to forward them directly to
+   * #GSimpleAction::change-state.  This should allow almost all users
+   * of #GSimpleAction to connect only one handler or the other.
+   *
    * Since: 2.28
    */
   g_simple_action_signals[SIGNAL_ACTIVATE] =