hook gvariant vectors up to kdbus
[platform/upstream/glib.git] / gio / gsimpleaction.c
index 2456b16..610e2fa 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Authors: Ryan Lortie <desrt@desrt.ca>
  */
 /**
  * SECTION:gsimpleaction
  * @title: GSimpleAction
- * @short_description: A simple GSimpleAction
+ * @short_description: A simple GAction implementation
+ * @include: gio/gio.h
  *
  * A #GSimpleAction is the obvious simple implementation of the #GAction
- * interface.  This is the easiest way to create an action for purposes of
+ * interface. This is the easiest way to create an action for purposes of
  * adding it to a #GSimpleActionGroup.
  *
  * See also #GtkAction.
- **/
+ */
 struct _GSimpleAction
 {
   GObject       parent_instance;
@@ -45,6 +44,7 @@ struct _GSimpleAction
   GVariantType *parameter_type;
   gboolean      enabled;
   GVariant     *state;
+  gboolean      state_set_already;
 };
 
 typedef GObjectClass GSimpleActionClass;
@@ -80,7 +80,7 @@ g_simple_action_get_name (GAction *action)
   return simple->name;
 }
 
-const GVariantType *
+static const GVariantType *
 g_simple_action_get_parameter_type (GAction *action)
 {
   GSimpleAction *simple = G_SIMPLE_ACTION (action);
@@ -144,6 +144,8 @@ g_simple_action_change_state (GAction  *action,
  * property.  Instead, they should call g_action_change_state() to
  * request the change.
  *
+ * If the @value GVariant is floating, it is consumed.
+ *
  * Since: 2.30
  **/
 void
@@ -201,13 +203,78 @@ 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_ACTIVATE], 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);
 }
 
 static void
+g_simple_action_set_property (GObject    *object,
+                              guint       prop_id,
+                              const GValue     *value,
+                              GParamSpec *pspec)
+{
+  GSimpleAction *action = G_SIMPLE_ACTION (object);
+
+  switch (prop_id)
+    {
+    case PROP_NAME:
+      action->name = g_strdup (g_value_get_string (value));
+      break;
+
+    case PROP_PARAMETER_TYPE:
+      action->parameter_type = g_value_dup_boxed (value);
+      break;
+
+    case PROP_ENABLED:
+      action->enabled = g_value_get_boolean (value);
+      break;
+
+    case PROP_STATE:
+      /* The first time we see this (during construct) we should just
+       * take the state as it was handed to us.
+       *
+       * After that, we should make sure we go through the same checks
+       * as the C API.
+       */
+      if (!action->state_set_already)
+        {
+          action->state = g_value_dup_variant (value);
+          action->state_set_already = TRUE;
+        }
+      else
+        g_simple_action_set_state (action, g_value_get_variant (value));
+
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
 g_simple_action_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
@@ -260,6 +327,7 @@ g_simple_action_finalize (GObject *object)
 void
 g_simple_action_init (GSimpleAction *simple)
 {
+  simple->enabled = TRUE;
 }
 
 void
@@ -280,6 +348,7 @@ g_simple_action_class_init (GSimpleActionClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
 
+  object_class->set_property = g_simple_action_set_property;
   object_class->get_property = g_simple_action_get_property;
   object_class->finalize = g_simple_action_finalize;
 
@@ -293,6 +362,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] =
@@ -317,13 +394,12 @@ g_simple_action_class_init (GSimpleActionClass *class)
    *
    * If no handler is connected to this signal then the default
    * behaviour is to call g_simple_action_set_state() to set the state
-   * to the requested value.  If you connect a signal handler then no
-   * default action is taken.  If the state should change then you must
+   * to the requested value. If you connect a signal handler then no
+   * default action is taken. If the state should change then you must
    * call g_simple_action_set_state() from the handler.
    *
-   * <example>
-   * <title>Example 'change-state' handler</title>
-   * <programlisting>
+   * An example of a 'change-state' handler:
+   * |[<!-- language="C" -->
    * static void
    * change_volume_state (GSimpleAction *action,
    *                      GVariant      *value,
@@ -337,11 +413,10 @@ g_simple_action_class_init (GSimpleActionClass *class)
    *   if (0 <= requested && requested <= 10)
    *     g_simple_action_set_state (action, value);
    * }
-   * </programlisting>
-   * </example>
+   * ]|
    *
-   * The handler need not set the state to the requested value.  It
-   * could set it to any value at all, or take some other action.
+   * The handler need not set the state to the requested value.
+   * It could set it to any value at all, or take some other action.
    *
    * Since: 2.30
    */
@@ -357,7 +432,7 @@ g_simple_action_class_init (GSimpleActionClass *class)
   /**
    * GSimpleAction:name:
    *
-   * The name of the action.  This is mostly meaningful for identifying
+   * The name of the action. This is mostly meaningful for identifying
    * the action once it has been added to a #GSimpleActionGroup.
    *
    * Since: 2.28
@@ -367,7 +442,8 @@ g_simple_action_class_init (GSimpleActionClass *class)
                                                         P_("Action Name"),
                                                         P_("The name used to invoke the action"),
                                                         NULL,
-                                                        G_PARAM_READABLE |
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
                                                         G_PARAM_STATIC_STRINGS));
 
   /**
@@ -383,7 +459,8 @@ g_simple_action_class_init (GSimpleActionClass *class)
                                                        P_("Parameter Type"),
                                                        P_("The type of GVariant passed to activate()"),
                                                        G_TYPE_VARIANT_TYPE,
-                                                       G_PARAM_READABLE |
+                                                       G_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT_ONLY |
                                                        G_PARAM_STATIC_STRINGS));
 
   /**
@@ -401,7 +478,7 @@ g_simple_action_class_init (GSimpleActionClass *class)
                                                          P_("Enabled"),
                                                          P_("If the action can be activated"),
                                                          TRUE,
-                                                         G_PARAM_READABLE |
+                                                         G_PARAM_READWRITE |
                                                          G_PARAM_STATIC_STRINGS));
 
   /**
@@ -433,7 +510,7 @@ g_simple_action_class_init (GSimpleActionClass *class)
                                                          P_("The state the action is in"),
                                                          G_VARIANT_TYPE_ANY,
                                                          NULL,
-                                                         G_PARAM_READABLE |
+                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
                                                          G_PARAM_STATIC_STRINGS));
 }
 
@@ -483,19 +560,10 @@ GSimpleAction *
 g_simple_action_new (const gchar        *name,
                      const GVariantType *parameter_type)
 {
-  GSimpleAction *simple;
-
-  g_return_val_if_fail (name != NULL, NULL);
-
-  simple = g_object_new (G_TYPE_SIMPLE_ACTION, NULL);
-  simple->name = g_strdup (name);
-
-  if (parameter_type)
-    simple->parameter_type = g_variant_type_copy (parameter_type);
-
-  simple->enabled = TRUE;
-
-  return simple;
+  return g_object_new (G_TYPE_SIMPLE_ACTION,
+                       "name", name,
+                       "parameter-type", parameter_type,
+                       NULL);
 }
 
 /**
@@ -520,20 +588,9 @@ g_simple_action_new_stateful (const gchar        *name,
                               const GVariantType *parameter_type,
                               GVariant           *state)
 {
-  GSimpleAction *simple;
-
-  g_return_val_if_fail (name != NULL, NULL);
-  g_return_val_if_fail (state != NULL, NULL);
-
-  simple = g_object_new (G_TYPE_SIMPLE_ACTION, NULL);
-  simple->name = g_strdup (name);
-
-  if (parameter_type)
-    simple->parameter_type = g_variant_type_copy (parameter_type);
-
-  simple->state = g_variant_ref_sink (state);
-
-  simple->enabled = TRUE;
-
-  return simple;
+  return g_object_new (G_TYPE_SIMPLE_ACTION,
+                       "name", name,
+                       "parameter-type", parameter_type,
+                       "state", state,
+                       NULL);
 }