From 8f2b343fc59a927961ee90f588f207d22c54924d Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 28 Jun 2012 16:07:17 +0200 Subject: libmessaging-menu: use the (newly added) GTupleAction instead of GSimpleAction GTupleAction is a bit simpler to handle when the action state contains a tuple of things that are independently modified most the time. It might be useful for other indicators as well. This implicitly also fixes the bug that libmessaging-menu did not preserve the other values in the action state when updating count, time, or string. --- libmessaging-menu/Makefile.am | 2 + libmessaging-menu/gtupleaction.c | 353 +++++++++++++++++++++++++++++++++++++ libmessaging-menu/gtupleaction.h | 40 +++++ libmessaging-menu/messaging-menu.c | 71 +++----- 4 files changed, 422 insertions(+), 44 deletions(-) create mode 100644 libmessaging-menu/gtupleaction.c create mode 100644 libmessaging-menu/gtupleaction.h (limited to 'libmessaging-menu') diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index a0da51e..becaded 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -5,6 +5,8 @@ libmessaging_menu_ladir = $(includedir)/messaging-menu libmessaging_menu_la_SOURCES = \ messaging-menu.c \ + gtupleaction.c \ + gtupleaction.h \ $(BUILT_SOURCES) libmessaging_menu_la_HEADERS = \ diff --git a/libmessaging-menu/gtupleaction.c b/libmessaging-menu/gtupleaction.c new file mode 100644 index 0000000..f9e6fd7 --- /dev/null +++ b/libmessaging-menu/gtupleaction.c @@ -0,0 +1,353 @@ +/* + * 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) +{ +} + +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]); +} diff --git a/libmessaging-menu/gtupleaction.h b/libmessaging-menu/gtupleaction.h new file mode 100644 index 0000000..c447d71 --- /dev/null +++ b/libmessaging-menu/gtupleaction.h @@ -0,0 +1,40 @@ +/* + * 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 + */ + +#ifndef __g_tuple_action_h__ +#define __g_tuple_action_h__ + +#include + +#define G_TYPE_TUPLE_ACTION (g_tuple_action_get_type ()) +#define G_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TUPLE_ACTION, GTupleAction)) +#define G_IS_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TUPLE_ACTION)) + +typedef struct _GTupleAction GTupleAction; + +GType g_tuple_action_get_type (void) G_GNUC_CONST; + +GTupleAction * g_tuple_action_new (const gchar *name, + GVariant *initial_state); + +void g_tuple_action_set_child (GTupleAction *action, + gsize index, + GVariant *value); + +#endif diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 7ee455a..22e4793 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -19,6 +19,7 @@ #include "messaging-menu.h" #include "indicator-messages-service.h" +#include "gtupleaction.h" #include @@ -44,6 +45,14 @@ struct _MessagingMenuApp G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT); +enum +{ + INDEX_COUNT, + INDEX_TIME, + INDEX_STRING, + INDEX_DRAWS_ATTENTION +}; + enum { PROP_0, PROP_DESKTOP_ID, @@ -392,9 +401,9 @@ global_status_changed (IndicatorMessagesService *service, } static void -source_action_activated (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +source_action_activated (GTupleAction *action, + GVariant *parameter, + gpointer user_data) { MessagingMenuApp *app = user_data; const gchar *name = g_action_get_name (G_ACTION (action)); @@ -411,7 +420,7 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, const gchar *label, GVariant *state) { - GSimpleAction *action; + GTupleAction *action; GMenuItem *menuitem; g_return_if_fail (MESSAGING_MENU_IS_APP (app)); @@ -423,7 +432,7 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, return; } - action = g_simple_action_new_stateful (id, NULL, state); + action = g_tuple_action_new (id, state); g_signal_connect (action, "activate", G_CALLBACK (source_action_activated), app); g_simple_action_group_insert (app->source_actions, G_ACTION (action)); @@ -443,7 +452,8 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, static void messaging_menu_app_set_source_action (MessagingMenuApp *app, const gchar *source_id, - GVariant *state) + gsize index, + GVariant *child) { GAction *action; @@ -457,7 +467,7 @@ messaging_menu_app_set_source_action (MessagingMenuApp *app, return; } - g_simple_action_set_state (G_SIMPLE_ACTION (action), state); + g_tuple_action_set_child (G_TUPLE_ACTION (action), index, child); } /** @@ -744,8 +754,8 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app, const gchar *source_id, guint count) { - messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxsb)", count, 0, "", FALSE)); + messaging_menu_app_set_source_action (app, source_id, INDEX_COUNT, + g_variant_new_uint32 (count)); } /** @@ -764,8 +774,8 @@ messaging_menu_app_set_source_time (MessagingMenuApp *app, const gchar *source_id, gint64 time) { - messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxsb)", 0, time, "", FALSE)); + messaging_menu_app_set_source_action (app, source_id, INDEX_TIME, + g_variant_new_int64 (time)); } /** @@ -784,37 +794,8 @@ messaging_menu_app_set_source_string (MessagingMenuApp *app, const gchar *source_id, const gchar *str) { - messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxsb)", 0, 0, str, FALSE)); -} - -static void -messaging_menu_app_set_attention (MessagingMenuApp *app, - const gchar *source_id, - gboolean attention) -{ - GAction *action; - GVariant *state; - guint32 count; - gint64 time; - const gchar *str =""; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - action = g_simple_action_group_lookup (app->source_actions, source_id); - if (action == NULL) - { - g_warning ("a source with id '%s' doesn't exist", source_id); - return; - } - - state = g_action_get_state (action); - g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); - g_variant_unref (state); - - g_simple_action_set_state (G_SIMPLE_ACTION (action), - g_variant_new ("(uxsb)", count, time, str, attention)); + messaging_menu_app_set_source_action (app, source_id, INDEX_STRING, + g_variant_new_string (str)); } /** @@ -832,7 +813,8 @@ void messaging_menu_app_draw_attention (MessagingMenuApp *app, const gchar *source_id) { - messaging_menu_app_set_attention (app, source_id, TRUE); + messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, + g_variant_new_boolean (TRUE)); } /** @@ -849,5 +831,6 @@ void messaging_menu_app_remove_attention (MessagingMenuApp *app, const gchar *source_id) { - messaging_menu_app_set_attention (app, source_id, FALSE); + messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, + g_variant_new_boolean (FALSE)); } -- cgit v1.2.3