aboutsummaryrefslogtreecommitdiff
path: root/libmessaging-menu/messaging-menu-message.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmessaging-menu/messaging-menu-message.c')
-rw-r--r--libmessaging-menu/messaging-menu-message.c547
1 files changed, 547 insertions, 0 deletions
diff --git a/libmessaging-menu/messaging-menu-message.c b/libmessaging-menu/messaging-menu-message.c
new file mode 100644
index 0000000..b81cbea
--- /dev/null
+++ b/libmessaging-menu/messaging-menu-message.c
@@ -0,0 +1,547 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#include "messaging-menu-message.h"
+
+typedef GObjectClass MessagingMenuMessageClass;
+
+struct _MessagingMenuMessage
+{
+ GObject parent;
+
+ gchar *id;
+ GIcon *icon;
+ gchar *title;
+ gchar *subtitle;
+ gchar *body;
+ gint64 time;
+ gboolean draws_attention;
+
+ GSList *actions;
+};
+
+G_DEFINE_TYPE (MessagingMenuMessage, messaging_menu_message, G_TYPE_OBJECT);
+
+enum
+{
+ PROP_0,
+ PROP_ID,
+ PROP_ICON,
+ PROP_TITLE,
+ PROP_SUBTITLE,
+ PROP_BODY,
+ PROP_TIME,
+ PROP_DRAWS_ATTENTION,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+typedef struct
+{
+ gchar *id;
+ gchar *label;
+ GVariantType *parameter_type;
+ GVariant *parameter_hint;
+} Action;
+
+static void
+action_free (gpointer data)
+{
+ Action *action = data;
+
+ g_free (action->id);
+ g_free (action->label);
+
+ if (action->parameter_type)
+ g_variant_type_free (action->parameter_type);
+
+ if (action->parameter_hint)
+ g_variant_unref (action->parameter_hint);
+
+ g_slice_free (Action, action);
+}
+
+static void
+messaging_menu_message_dispose (GObject *object)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ g_clear_object (&msg->icon);
+
+ G_OBJECT_CLASS (messaging_menu_message_parent_class)->dispose (object);
+}
+
+static void
+messaging_menu_message_finalize (GObject *object)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ g_free (msg->id);
+ g_free (msg->title);
+ g_free (msg->subtitle);
+ g_free (msg->body);
+
+ g_slist_free_full (msg->actions, action_free);
+ msg->actions = NULL;
+
+ G_OBJECT_CLASS (messaging_menu_message_parent_class)->finalize (object);
+}
+
+static void
+messaging_menu_message_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, msg->id);
+ break;
+
+ case PROP_ICON:
+ g_value_set_object (value, msg->icon);
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, msg->title);
+ break;
+
+ case PROP_SUBTITLE:
+ g_value_set_string (value, msg->subtitle);
+ break;
+
+ case PROP_BODY:
+ g_value_set_string (value, msg->body);
+
+ case PROP_TIME:
+ g_value_set_int64 (value, msg->time);
+ break;
+
+ case PROP_DRAWS_ATTENTION:
+ g_value_set_boolean (value, msg->draws_attention);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+messaging_menu_message_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MessagingMenuMessage *msg = MESSAGING_MENU_MESSAGE (object);
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ msg->id = g_value_dup_string (value);
+ break;
+
+ case PROP_ICON:
+ msg->icon = g_value_dup_object (value);
+ break;
+
+ case PROP_TITLE:
+ msg->title = g_value_dup_string (value);
+ break;
+
+ case PROP_SUBTITLE:
+ msg->subtitle = g_value_dup_string (value);
+ break;
+
+ case PROP_BODY:
+ msg->body = g_value_dup_string (value);
+
+ case PROP_TIME:
+ msg->time = g_value_get_int64 (value);
+ break;
+
+ case PROP_DRAWS_ATTENTION:
+ messaging_menu_message_set_draws_attention (msg, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+messaging_menu_message_class_init (MessagingMenuMessageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = messaging_menu_message_dispose;
+ object_class->finalize = messaging_menu_message_finalize;
+ object_class->get_property = messaging_menu_message_get_property;
+ object_class->set_property = messaging_menu_message_set_property;
+
+ properties[PROP_ID] = g_param_spec_string ("id", "Id",
+ "Unique id of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] = g_param_spec_object ("icon", "Icon",
+ "Icon of the message",
+ G_TYPE_ICON,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TITLE] = g_param_spec_string ("title", "Title",
+ "Title of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_SUBTITLE] = g_param_spec_string ("subtitle", "Subtitle",
+ "Subtitle of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_BODY] = g_param_spec_string ("body", "Body",
+ "First lines of the body of the message",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TIME] = g_param_spec_int64 ("time", "Time",
+ "Time the message was sent, in microseconds", 0, G_MAXINT64, 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention", "Draws attention",
+ "Whether the message should draw attention",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (klass, NUM_PROPERTIES, properties);
+
+ /**
+ * MessagingMenuMessage::activate:
+ * @msg: the #MessagingMenuMessage
+ * @action: (allow-none): the id of activated action, or %NULL
+ * @parameter: (allow-none): activation parameter, or %NULL
+ *
+ * Emitted when the user has activated the message. The message is
+ * immediately removed from the application's menu, handlers of this
+ * signal do not need to call messaging_menu_app_remove_message().
+ */
+ g_signal_new ("activate",
+ MESSAGING_MENU_TYPE_MESSAGE,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_VARIANT);
+}
+
+static void
+messaging_menu_message_init (MessagingMenuMessage *self)
+{
+}
+
+/**
+ * messaging_menu_message_new:
+ * @id: unique id of the message
+ * @icon: (transfer full) (allow-none): a #GIcon representing the message
+ * @title: the title of the message
+ * @subtitle: (allow-none): the subtitle of the message
+ * @body: (allow-none): the message body
+ * @time: the time the message was received
+ *
+ * Creates a new #MessagingMenuMessage.
+ *
+ * Returns: (transfer full): a new #MessagingMenuMessage
+ */
+MessagingMenuMessage *
+messaging_menu_message_new (const gchar *id,
+ GIcon *icon,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *body,
+ gint64 time)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+ g_return_val_if_fail (title != NULL, NULL);
+
+ return g_object_new (MESSAGING_MENU_TYPE_MESSAGE,
+ "id", id,
+ "icon", icon,
+ "title", title,
+ "subtitle", subtitle,
+ "body", body,
+ "time", time,
+ NULL);
+}
+
+/**
+ * messaging_menu_message_get_id:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the unique id of @msg
+ */
+const gchar *
+messaging_menu_message_get_id (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->id;
+}
+
+/**
+ * messaging_menu_message_get_icon:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: (transfer none): the icon of @msg
+ */
+GIcon *
+messaging_menu_message_get_icon (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->icon;
+}
+
+/**
+ * messaging_menu_message_get_title:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the title of @msg
+ */
+const gchar *
+messaging_menu_message_get_title (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->title;
+}
+
+/**
+ * messaging_menu_message_get_subtitle:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the subtitle of @msg
+ */
+const gchar *
+messaging_menu_message_get_subtitle (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->subtitle;
+}
+
+/**
+ * messaging_menu_message_get_body:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the body of @msg
+ */
+const gchar *
+messaging_menu_message_get_body (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ return msg->body;
+}
+
+/**
+ * messaging_menu_message_get_time:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: the time at which @msg was received
+ */
+gint64
+messaging_menu_message_get_time (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), 0);
+
+ return msg->time;
+}
+
+/**
+ * messaging_menu_message_get_draws_attention:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Returns: whether @msg is drawing attention
+ */
+gboolean
+messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), FALSE);
+
+ return msg->draws_attention;
+}
+
+/**
+ * messaging_menu_message_set_draws_attention:
+ * @msg: a #MessagingMenuMessage
+ * @draws_attention: whether @msg should draw attention
+ *
+ * Sets whether @msg is drawing attention.
+ */
+void
+messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg,
+ gboolean draws_attention)
+{
+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
+
+ msg->draws_attention = draws_attention;
+ g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_DRAWS_ATTENTION]);
+}
+
+/**
+ * messaging_menu_message_add_action:
+ * @msg: a #MessagingMenuMessage
+ * @id: unique id of the action
+ * @label: (allow-none): label of the action
+ * @parameter_type: (allow-none): a #GVariantType
+ * @parameter_hint: (allow-none): a #GVariant suggesting a valid range
+ * for parameters
+ *
+ * Adds an action with @id and @label to @message. Actions are an
+ * alternative way for users to activate a message. Note that messages
+ * can still be activated without an action.
+ *
+ * If @parameter_type is non-%NULL, the action is able to receive user
+ * input in addition to simply activating the action. Currently, only
+ * string parameters are supported.
+ *
+ * A list of predefined parameters can be supplied as a #GVariant array
+ * of @parameter_type in @parameter_hint. If @parameter_hint is
+ * floating, it will be consumed.
+ *
+ * It is recommended to add at most two actions to a message.
+ */
+void
+messaging_menu_message_add_action (MessagingMenuMessage *msg,
+ const gchar *id,
+ const gchar *label,
+ const GVariantType *parameter_type,
+ GVariant *parameter_hint)
+{
+ Action *action;
+
+ g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg));
+ g_return_if_fail (id != NULL);
+
+ action = g_slice_new (Action);
+ action->id = g_strdup (id);
+ action->label = g_strdup (label);
+ action->parameter_type = parameter_type ? g_variant_type_copy (parameter_type) : NULL;
+ action->parameter_hint = parameter_hint ? g_variant_ref_sink (parameter_hint) : NULL;
+
+ msg->actions = g_slist_append (msg->actions, action);
+}
+
+static GVariant *
+action_to_variant (Action *action)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string (action->id));
+
+ if (action->label)
+ g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (action->label));
+
+ if (action->parameter_type)
+ {
+ gchar *type = g_variant_type_dup_string (action->parameter_type);
+ g_variant_builder_add (&builder, "{sv}", "parameter-type", g_variant_new_signature (type));
+ g_free (type);
+ }
+
+ if (action->parameter_hint)
+ g_variant_builder_add (&builder, "{sv}", "parameter-hint", action->parameter_hint);
+
+ return g_variant_builder_end (&builder);
+}
+
+/*<internal>
+ * _messaging_menu_message_to_variant:
+ * @msg: a #MessagingMenuMessage
+ *
+ * Serializes @msg to a #GVariant of the form (sssssxaa{sv}b):
+ *
+ * id
+ * icon
+ * title
+ * subtitle
+ * body
+ * time
+ * array of action dictionaries
+ * draws_attention
+ *
+ * Returns: a new floating #GVariant instance
+ */
+GVariant *
+_messaging_menu_message_to_variant (MessagingMenuMessage *msg)
+{
+ GVariantBuilder builder;
+ GSList *it;
+
+ g_return_val_if_fail (MESSAGING_MENU_IS_MESSAGE (msg), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sssssxaa{sv}b)"));
+
+ g_variant_builder_add (&builder, "s", msg->id);
+
+ if (msg->icon)
+ {
+ gchar *iconstr;
+
+ iconstr = g_icon_to_string (msg->icon);
+ g_variant_builder_add (&builder, "s", iconstr);
+
+ g_free (iconstr);
+ }
+ else
+ g_variant_builder_add (&builder, "s", "");
+
+ g_variant_builder_add (&builder, "s", msg->title ? msg->title : "");
+ g_variant_builder_add (&builder, "s", msg->subtitle ? msg->subtitle : "");
+ g_variant_builder_add (&builder, "s", msg->body ? msg->body : "");
+ g_variant_builder_add (&builder, "x", msg->time);
+
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("aa{sv}"));
+ for (it = msg->actions; it; it = it->next)
+ g_variant_builder_add_value (&builder, action_to_variant (it->data));
+ g_variant_builder_close (&builder);
+
+ g_variant_builder_add (&builder, "b", msg->draws_attention);
+
+ return g_variant_builder_end (&builder);
+}