/* * Copyright 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Lars Uebernickel */ #include "gtupleaction.h" typedef GObjectClass GTupleActionClass; struct _GTupleAction { GObject parent; gchar *name; GVariantType *type; gboolean enabled; gsize n_children; GVariant **children; }; static void action_interface_init (GActionInterface *iface); G_DEFINE_TYPE_WITH_CODE (GTupleAction, g_tuple_action, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_interface_init)); enum { PROP_0, PROP_NAME, PROP_PARAMETER_TYPE, PROP_ENABLED, PROP_STATE_TYPE, PROP_STATE, N_PROPERTIES }; enum { SIGNAL_ACTIVATE, N_SIGNALS }; static GParamSpec *properties[N_PROPERTIES]; static guint signal_ids[N_SIGNALS]; static const gchar * g_tuple_action_get_name (GAction *action) { GTupleAction *tuple = G_TUPLE_ACTION (action); return tuple->name; } static const GVariantType * g_tuple_action_get_parameter_type (GAction *action) { return NULL; } static const GVariantType * g_tuple_action_get_state_type (GAction *action) { GTupleAction *tuple = G_TUPLE_ACTION (action); return tuple->type; } static GVariant * g_tuple_action_get_state_hint (GAction *action) { return NULL; } static gboolean g_tuple_action_get_enabled (GAction *action) { GTupleAction *tuple = G_TUPLE_ACTION (action); return tuple->enabled; } static GVariant * g_tuple_action_get_state (GAction *action) { GTupleAction *tuple = G_TUPLE_ACTION (action); GVariant *result; result = g_variant_new_tuple (tuple->children, tuple->n_children); return g_variant_ref_sink (result); } static void g_tuple_action_set_state (GTupleAction *tuple, GVariant *state) { int i; g_return_if_fail (g_variant_type_is_tuple (g_variant_get_type (state))); if (tuple->type == NULL) { tuple->type = g_variant_type_copy (g_variant_get_type (state)); tuple->n_children = g_variant_n_children (state); tuple->children = g_new0 (GVariant *, tuple->n_children); } for (i = 0; i < tuple->n_children; i++) { if (tuple->children[i]) g_variant_unref (tuple->children[i]); tuple->children[i] = g_variant_get_child_value (state, i); } g_object_notify_by_pspec (G_OBJECT (tuple), properties[PROP_STATE]); } static void g_tuple_action_change_state (GAction *action, GVariant *value) { GTupleAction *tuple = G_TUPLE_ACTION (action); g_return_if_fail (value != NULL); g_return_if_fail (g_variant_is_of_type (value, tuple->type)); g_variant_ref_sink (value); /* TODO add a change-state signal similar to GSimpleAction */ g_tuple_action_set_state (tuple, value); g_variant_unref (value); } static void g_tuple_action_activate (GAction *action, GVariant *parameter) { GTupleAction *tuple = G_TUPLE_ACTION (action); g_return_if_fail (parameter == NULL); if (tuple->enabled) g_signal_emit (tuple, signal_ids[SIGNAL_ACTIVATE], 0, NULL); } static void g_tuple_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_tuple_action_get_name (action)); break; case PROP_PARAMETER_TYPE: g_value_set_boxed (value, g_tuple_action_get_parameter_type (action)); break; case PROP_ENABLED: g_value_set_boolean (value, g_tuple_action_get_enabled (action)); break; case PROP_STATE_TYPE: g_value_set_boxed (value, g_tuple_action_get_state_type (action)); break; case PROP_STATE: g_value_take_variant (value, g_tuple_action_get_state (action)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void g_tuple_action_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GTupleAction *tuple = G_TUPLE_ACTION (object); switch (prop_id) { case PROP_NAME: tuple->name = g_value_dup_string (value); g_object_notify_by_pspec (object, properties[PROP_NAME]); break; case PROP_ENABLED: tuple->enabled = g_value_get_boolean (value); g_object_notify_by_pspec (object, properties[PROP_ENABLED]); break; case PROP_STATE: g_tuple_action_set_state (tuple, g_value_get_variant (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void g_tuple_action_finalize (GObject *object) { GTupleAction *tuple = G_TUPLE_ACTION (object); int i; g_free (tuple->name); g_variant_type_free (tuple->type); for (i = 0; i < tuple->n_children; i++) g_variant_unref (tuple->children[i]); g_free (tuple->children); G_OBJECT_CLASS (g_tuple_action_parent_class)->finalize (object); } static void action_interface_init (GActionInterface *iface) { iface->get_name = g_tuple_action_get_name; iface->get_parameter_type = g_tuple_action_get_parameter_type; iface->get_state_type = g_tuple_action_get_state_type; iface->get_state_hint = g_tuple_action_get_state_hint; iface->get_enabled = g_tuple_action_get_enabled; iface->get_state = g_tuple_action_get_state; iface->change_state = g_tuple_action_change_state; iface->activate = g_tuple_action_activate; } static void g_tuple_action_class_init (GTupleActionClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->get_property = g_tuple_action_get_property; object_class->set_property = g_tuple_action_set_property; object_class->finalize = g_tuple_action_finalize; properties[PROP_NAME] = g_param_spec_string ("name", "Name", "The name of the action", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type", "Parameter Type", "The variant type passed to activate", G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PROP_ENABLED] = g_param_spec_boolean ("enabled", "Enabled", "Whether the action can be activated", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type", "State Type", "The variant type of the state, must be a tuple", G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PROP_STATE] = g_param_spec_variant ("state", "State", "The state of the action", G_VARIANT_TYPE_TUPLE, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPERTIES, properties); signal_ids[SIGNAL_ACTIVATE] = g_signal_new ("activate", G_TYPE_TUPLE_ACTION, G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT, 0, NULL, NULL, g_cclosure_marshal_VOID__VARIANT, G_TYPE_NONE, 1, G_TYPE_VARIANT); } static void g_tuple_action_init (GTupleAction *action) { action->enabled = TRUE; } GTupleAction * g_tuple_action_new (const gchar *name, GVariant *initial_state) { const GVariantType *type; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (initial_state != NULL, NULL); type = g_variant_get_type (initial_state); g_return_val_if_fail (g_variant_type_is_tuple (type), NULL); return g_object_new (G_TYPE_TUPLE_ACTION, "name", name, "state", initial_state, NULL); } void g_tuple_action_set_child (GTupleAction *action, gsize index, GVariant *value) { const GVariantType *type; g_return_if_fail (G_IS_TUPLE_ACTION (action)); g_return_if_fail (index < action->n_children); g_return_if_fail (value != NULL); type = g_variant_get_type (value); g_return_if_fail (g_variant_is_of_type (value, type)); g_variant_unref (action->children[index]); action->children[index] = g_variant_ref_sink (value); g_object_notify_by_pspec (G_OBJECT (action), properties[PROP_STATE]); }