/* * Copyright © 2010 Codethink Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2 of the licence or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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. * * Authors: Ryan Lortie */ #include "config.h" #include "gsimpleaction.h" #include "gaction.h" #include "glibintl.h" static void g_simple_action_iface_init (GActionInterface *iface); G_DEFINE_TYPE_WITH_CODE (GSimpleAction, g_simple_action, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_simple_action_iface_init)) /** * SECTION:gsimpleaction * @title: GSimpleAction * @short_description: a simple #GSimpleAction * * A #GSimpleAction is the obvious simple implementation of the #GSimpleAction * interface. This is the easiest way to create an action for purposes of * adding it to a #GSimpleActionGroup. * * See also #GtkAction. **/ struct _GSimpleActionPrivate { gchar *name; GVariantType *parameter_type; guint enabled : 1; guint state_set : 1; GVariant *state; }; enum { PROP_NONE, PROP_NAME, PROP_PARAMETER_TYPE, PROP_ENABLED, PROP_STATE_TYPE, PROP_STATE }; enum { SIGNAL_ACTIVATE, NR_SIGNALS }; static guint g_simple_action_signals[NR_SIGNALS]; static const gchar * g_simple_action_get_name (GAction *action) { GSimpleAction *simple = G_SIMPLE_ACTION (action); return simple->priv->name; } const GVariantType * g_simple_action_get_parameter_type (GAction *action) { GSimpleAction *simple = G_SIMPLE_ACTION (action); return simple->priv->parameter_type; } static const GVariantType * g_simple_action_get_state_type (GAction *action) { GSimpleAction *simple = G_SIMPLE_ACTION (action); if (simple->priv->state != NULL) return g_variant_get_type (simple->priv->state); else return NULL; } static GVariant * g_simple_action_get_state_hint (GAction *action) { return NULL; } static gboolean g_simple_action_get_enabled (GAction *action) { GSimpleAction *simple = G_SIMPLE_ACTION (action); return simple->priv->enabled; } static void g_simple_action_set_state (GAction *action, GVariant *value) { GSimpleAction *simple = G_SIMPLE_ACTION (action); g_return_if_fail (value != NULL); { const GVariantType *state_type; state_type = simple->priv->state ? g_variant_get_type (simple->priv->state) : NULL; g_return_if_fail (state_type != NULL); g_return_if_fail (g_variant_is_of_type (value, state_type)); } g_variant_ref_sink (value); if (!g_variant_equal (simple->priv->state, value)) { if (simple->priv->state) g_variant_unref (simple->priv->state); simple->priv->state = g_variant_ref (value); g_object_notify (G_OBJECT (simple), "state"); } g_variant_unref (value); } static GVariant * g_simple_action_get_state (GAction *action) { GSimpleAction *simple = G_SIMPLE_ACTION (action); return simple->priv->state ? g_variant_ref (simple->priv->state) : NULL; } static void g_simple_action_activate (GAction *action, GVariant *parameter) { GSimpleAction *simple = G_SIMPLE_ACTION (action); g_return_if_fail (simple->priv->parameter_type == NULL ? parameter == NULL : (parameter != NULL && g_variant_is_of_type (parameter, simple->priv->parameter_type))); if (parameter != NULL) g_variant_ref_sink (parameter); if (simple->priv->enabled) g_signal_emit (simple, g_simple_action_signals[SIGNAL_ACTIVATE], 0, 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 *simple = G_SIMPLE_ACTION (object); switch (prop_id) { case PROP_NAME: g_assert (simple->priv->name == NULL); simple->priv->name = g_value_dup_string (value); break; case PROP_PARAMETER_TYPE: g_assert (simple->priv->parameter_type == NULL); simple->priv->parameter_type = g_value_dup_boxed (value); break; case PROP_ENABLED: g_simple_action_set_enabled (simple, g_value_get_boolean (value)); break; case PROP_STATE: /* PROP_STATE is marked as G_PARAM_CONSTRUCT so we always get a * call during object construction, even if it is NULL. We treat * that first call differently, for a number of reasons. * * First, we don't want the value to be rejected by the * possibly-overridden .set_state() function. Second, we don't * want to be tripped by the assertions in g_simple_action_set_state() * that would enforce the catch22 that we only provide a value of * the same type as the existing value (when there is not yet an * existing value). */ if (simple->priv->state_set) g_simple_action_set_state (G_ACTION (simple), g_value_get_variant (value)); else /* this is the special case */ { /* only do it the first time. */ simple->priv->state_set = TRUE; /* blindly set it. */ simple->priv->state = g_value_dup_variant (value); } break; default: g_assert_not_reached (); } } static void g_simple_action_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GAction *action = G_ACTION (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, g_simple_action_get_name (action)); break; case PROP_PARAMETER_TYPE: g_value_set_boxed (value, g_simple_action_get_parameter_type (action)); break; case PROP_ENABLED: g_value_set_boolean (value, g_simple_action_get_enabled (action)); break; case PROP_STATE_TYPE: g_value_set_boxed (value, g_simple_action_get_state_type (action)); break; case PROP_STATE: g_value_take_variant (value, g_simple_action_get_state (action)); break; default: g_assert_not_reached (); } } static void g_simple_action_finalize (GObject *object) { GSimpleAction *simple = G_SIMPLE_ACTION (object); g_free (simple->priv->name); if (simple->priv->parameter_type) g_variant_type_free (simple->priv->parameter_type); if (simple->priv->state) g_variant_unref (simple->priv->state); G_OBJECT_CLASS (g_simple_action_parent_class) ->finalize (object); } void g_simple_action_init (GSimpleAction *simple) { simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (simple, G_TYPE_SIMPLE_ACTION, GSimpleActionPrivate); } void g_simple_action_iface_init (GActionInterface *iface) { iface->get_name = g_simple_action_get_name; iface->get_parameter_type = g_simple_action_get_parameter_type; iface->get_state_type = g_simple_action_get_state_type; iface->get_state_hint = g_simple_action_get_state_hint; iface->get_enabled = g_simple_action_get_enabled; iface->get_state = g_simple_action_get_state; iface->set_state = g_simple_action_set_state; iface->activate = g_simple_action_activate; } void g_simple_action_class_init (GSimpleActionClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->get_property = g_simple_action_get_property; object_class->set_property = g_simple_action_set_property; object_class->finalize = g_simple_action_finalize; /** * GSimpleAction::activate: * @simple: the #GSimpleAction * @parameter: (allow-none): the parameter to the activation * * Indicates that the action was just activated. * * @parameter will always be of the expected type. In the event that * an incorrect type was given, no signal will be emitted. * * Since: 2.28 */ g_simple_action_signals[SIGNAL_ACTIVATE] = g_signal_new (I_("activate"), G_TYPE_SIMPLE_ACTION, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GSimpleActionClass, activate), NULL, NULL, g_cclosure_marshal_VOID__VARIANT, G_TYPE_NONE, 1, G_TYPE_VARIANT); /** * GSimpleAction:name: * * The name of the action. This is mostly meaningful for identifying * the action once it has been added to a #GSimpleActionGroup. * * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", P_("Action Name"), P_("The name used to invoke the action"), NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * GSimpleAction:parameter-type: * * The type of the parameter that must be given when activating the * action. * * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_PARAMETER_TYPE, g_param_spec_boxed ("parameter-type", P_("Parameter Type"), P_("The type of GVariant passed to activate()"), G_TYPE_VARIANT_TYPE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * GSimpleAction:enabled: * * If @action is currently enabled. * * If the action is disabled then calls to g_simple_action_activate() and * g_simple_action_set_state() have no effect. * * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_ENABLED, g_param_spec_boolean ("enabled", P_("Enabled"), P_("If the action can be activated"), TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GSimpleAction:state-type: * * The #GVariantType of the state that the action has, or %NULL if the * action is stateless. * * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_STATE_TYPE, g_param_spec_boxed ("state-type", P_("State Type"), P_("The type of the state kept by the action"), G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GSimpleAction:state: * * The state of the action, or %NULL if the action is stateless. * * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_STATE, g_param_spec_variant ("state", P_("State"), P_("The state the action is in"), G_VARIANT_TYPE_ANY, NULL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_type_class_add_private (class, sizeof (GSimpleActionPrivate)); } /** * g_simple_action_set_enabled: * @simple: a #GSimpleAction * @enabled: whether the action is enabled * * Sets the action as enabled or not. * * An action must be enabled in order to be activated or in order to * have its state changed from outside callers. * * Since: 2.28 **/ void g_simple_action_set_enabled (GSimpleAction *simple, gboolean enabled) { g_return_if_fail (G_IS_SIMPLE_ACTION (simple)); enabled = !!enabled; if (simple->priv->enabled != enabled) { simple->priv->enabled = enabled; g_object_notify (G_OBJECT (simple), "enabled"); } } /** * g_simple_action_new: * @name: the name of the action * @parameter_type: (allow-none): the type of parameter to the activate function * * Creates a new action. * * The created action is stateless. See g_simple_action_new_stateful(). * * Returns: a new #GSimpleAction * * Since: 2.28 **/ GSimpleAction * g_simple_action_new (const gchar *name, const GVariantType *parameter_type) { return g_object_new (G_TYPE_SIMPLE_ACTION, "name", name, "parameter-type", parameter_type, NULL); } /** * g_simple_action_new_stateful: * @name: the name of the action * @parameter_type: (allow-none): the type of the parameter to the activate function * @state: the initial state of the action * * Creates a new stateful action. * * @state is the initial state of the action. All future state values * must have the same #GVariantType as the initial state. * * If the @state GVariant is floating, it is consumed. * * Returns: a new #GSimpleAction * * Since: 2.28 **/ GSimpleAction * g_simple_action_new_stateful (const gchar *name, const GVariantType *parameter_type, GVariant *state) { return g_object_new (G_TYPE_SIMPLE_ACTION, "name", name, "parameter-type", parameter_type, "state", state, NULL); }