diff options
author | Łukasz 'sil2100' Zemczak <lukasz.zemczak@canonical.com> | 2013-08-20 10:53:01 +0200 |
---|---|---|
committer | Łukasz 'sil2100' Zemczak <lukasz.zemczak@canonical.com> | 2013-08-20 10:53:01 +0200 |
commit | 88b2fd89ff0bc4be81acd8f6d5751dba96e295f8 (patch) | |
tree | 2f231acd79d96f697709586effbabb4928477c89 /libmessaging-menu | |
parent | b25532c6a307381f523a78b4b5fbdeb73896bb3d (diff) | |
download | ayatana-indicator-messages-88b2fd89ff0bc4be81acd8f6d5751dba96e295f8.tar.gz ayatana-indicator-messages-88b2fd89ff0bc4be81acd8f6d5751dba96e295f8.tar.bz2 ayatana-indicator-messages-88b2fd89ff0bc4be81acd8f6d5751dba96e295f8.zip |
Revert rev 352 as it is causing a SIGTRAP on start
Diffstat (limited to 'libmessaging-menu')
-rw-r--r-- | libmessaging-menu/Makefile.am | 55 | ||||
-rw-r--r-- | libmessaging-menu/gtupleaction.c | 354 | ||||
-rw-r--r-- | libmessaging-menu/gtupleaction.h | 40 | ||||
-rw-r--r-- | libmessaging-menu/messaging-menu-app.h | 163 | ||||
-rw-r--r-- | libmessaging-menu/messaging-menu-message.c | 547 | ||||
-rw-r--r-- | libmessaging-menu/messaging-menu-message.h | 70 | ||||
-rw-r--r-- | libmessaging-menu/messaging-menu.c (renamed from libmessaging-menu/messaging-menu-app.c) | 745 | ||||
-rw-r--r-- | libmessaging-menu/messaging-menu.h | 125 |
8 files changed, 796 insertions, 1303 deletions
diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index 1042d9f..7a6ee31 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -4,25 +4,36 @@ lib_LTLIBRARIES = libmessaging-menu.la libmessaging_menu_ladir = $(includedir)/messaging-menu libmessaging_menu_la_SOURCES = \ - messaging-menu-app.c \ - messaging-menu-message.c + messaging-menu.c \ + gtupleaction.c \ + gtupleaction.h \ + $(BUILT_SOURCES) libmessaging_menu_la_HEADERS = \ - messaging-menu-app.h \ - messaging-menu.h \ - messaging-menu-message.h + messaging-menu.h -libmessaging_menu_la_LIBADD = \ - $(GIO_LIBS) \ - $(top_builddir)/common/libmessaging-common.la +libmessaging_menu_la_LIBADD = $(GIO_LIBS) libmessaging_menu_la_CFLAGS = \ - -I$(top_builddir)/common \ $(GIO_CFLAGS) \ -Wall libmessaging_menu_la_LDFLAGS = -export-symbols-regex "^messaging_menu_.*" +BUILT_SOURCES = \ + indicator-messages-service.c \ + indicator-messages-service.h + +CLEANFILES = $(BUILT_SOURCES) + +indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml + $(AM_V_GEN) gdbus-codegen \ + --interface-prefix com.canonical.indicator.messages. \ + --generate-c-code indicator-messages-service \ + --c-namespace IndicatorMessages \ + $^ +indicator-messages-service.h: indicator-messages-service.c + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = messaging-menu.pc @@ -41,11 +52,7 @@ MessagingMenu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS) MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h" MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la -MessagingMenu_1_0_gir_FILES = \ - messaging-menu-app.c \ - messaging-menu-app.h \ - messaging-menu-message.c \ - messaging-menu-message.h +MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu INTROSPECTION_GIRS += MessagingMenu-1.0.gir @@ -55,23 +62,5 @@ gir_DATA = $(INTROSPECTION_GIRS) typelibdir = $(libdir)/girepository-1.0 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) -CLEANFILES = $(gir_DATA) $(typelib_DATA) - - -######################### -# VAPI Files -######################### - -if HAVE_VALA - -vapidir = $(datadir)/vala/vapi -vapi_DATA = MessagingMenu-1.0.vapi - -MessagingMenu-1.0.vapi: MessagingMenu-1.0.gir - $(VALA_API_GEN) --pkg gio-2.0 --library=MessagingMenu-1.0 $< - -CLEANFILES += $(vapi_DATA) - -endif - +CLEANFILES +=$(gir_DATA) $(typelib_DATA) endif diff --git a/libmessaging-menu/gtupleaction.c b/libmessaging-menu/gtupleaction.c new file mode 100644 index 0000000..21bc003 --- /dev/null +++ b/libmessaging-menu/gtupleaction.c @@ -0,0 +1,354 @@ +/* + * 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 "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]); +} 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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Lars Uebernickel <lars.uebernickel@canonical.com> + */ + +#ifndef __g_tuple_action_h__ +#define __g_tuple_action_h__ + +#include <gio/gio.h> + +#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-app.h b/libmessaging-menu/messaging-menu-app.h deleted file mode 100644 index c8097e1..0000000 --- a/libmessaging-menu/messaging-menu-app.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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> - */ - -#ifndef __messaging_menu_app_h__ -#define __messaging_menu_app_h__ - -#include <gio/gio.h> -#include "messaging-menu-message.h" - -G_BEGIN_DECLS - -#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type() -#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp)) -#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass)) -#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP)) - -/** - * MessagingMenuStatus: - * @MESSAGING_MENU_STATUS_AVAILABLE: available - * @MESSAGING_MENU_STATUS_AWAY: away - * @MESSAGING_MENU_STATUS_BUSY: busy - * @MESSAGING_MENU_STATUS_INVISIBLE: invisible - * @MESSAGING_MENU_STATUS_OFFLINE: offline - * - * An enumeration for the possible chat statuses the messaging menu can be in. - */ -typedef enum { - MESSAGING_MENU_STATUS_AVAILABLE, - MESSAGING_MENU_STATUS_AWAY, - MESSAGING_MENU_STATUS_BUSY, - MESSAGING_MENU_STATUS_INVISIBLE, - MESSAGING_MENU_STATUS_OFFLINE -} MessagingMenuStatus; - - -typedef GObjectClass MessagingMenuAppClass; -typedef struct _MessagingMenuApp MessagingMenuApp; - -GType messaging_menu_app_get_type (void) G_GNUC_CONST; - -MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id); - -void messaging_menu_app_register (MessagingMenuApp *app); -void messaging_menu_app_unregister (MessagingMenuApp *app); - -void messaging_menu_app_set_status (MessagingMenuApp *app, - MessagingMenuStatus status); - -void messaging_menu_app_insert_source (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label); - -void messaging_menu_app_append_source (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label); - -void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count); - -void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count); - -void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - gint64 time); - -void messaging_menu_app_append_source_with_time (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - gint64 time); - -void messaging_menu_app_append_source_with_string (MessagingMenuApp *app, - const gchar *id, - GIcon *icon, - const gchar *label, - const gchar *str); - -void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - const gchar *str); - -void messaging_menu_app_remove_source (MessagingMenuApp *app, - const gchar *source_id); - -gboolean messaging_menu_app_has_source (MessagingMenuApp *app, - const gchar *source_id); - -void messaging_menu_app_set_source_label (MessagingMenuApp *app, - const gchar *source_id, - const gchar *label); - -void messaging_menu_app_set_source_icon (MessagingMenuApp *app, - const gchar *source_id, - GIcon *icon); - -void messaging_menu_app_set_source_count (MessagingMenuApp *app, - const gchar *source_id, - guint count); - -void messaging_menu_app_set_source_time (MessagingMenuApp *app, - const gchar *source_id, - gint64 time); - -void messaging_menu_app_set_source_string (MessagingMenuApp *app, - const gchar *source_id, - const gchar *str); - -void messaging_menu_app_draw_attention (MessagingMenuApp *app, - const gchar *source_id); - -void messaging_menu_app_remove_attention (MessagingMenuApp *app, - const gchar *source_id); - -void messaging_menu_app_append_message (MessagingMenuApp *app, - MessagingMenuMessage *msg, - const gchar *source_id, - gboolean notify); - -MessagingMenuMessage * messaging_menu_app_get_message (MessagingMenuApp *app, - const gchar *id); - -void messaging_menu_app_remove_message (MessagingMenuApp *app, - MessagingMenuMessage *msg); - -void messaging_menu_app_remove_message_by_id (MessagingMenuApp *app, - const gchar *id); - -G_END_DECLS - -#endif diff --git a/libmessaging-menu/messaging-menu-message.c b/libmessaging-menu/messaging-menu-message.c deleted file mode 100644 index b81cbea..0000000 --- a/libmessaging-menu/messaging-menu-message.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * 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); -} diff --git a/libmessaging-menu/messaging-menu-message.h b/libmessaging-menu/messaging-menu-message.h deleted file mode 100644 index 4708246..0000000 --- a/libmessaging-menu/messaging-menu-message.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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> - */ - -#ifndef __messaging_menu_message_h__ -#define __messaging_menu_message_h__ - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define MESSAGING_MENU_TYPE_MESSAGE (messaging_menu_message_get_type ()) -#define MESSAGING_MENU_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessage)) -#define MESSAGING_MENU_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass)) -#define MESSAGING_MENU_IS_MESSAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MESSAGING_MENU_TYPE_MESSAGE)) -#define MESSAGING_MENU_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGING_MENU_TYPE_MESSAGE)) -#define MESSAGING_MENU_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGING_MENU_TYPE_MESSAGE, MessagingMenuMessageClass)) - -typedef struct _MessagingMenuMessage MessagingMenuMessage; - -GType messaging_menu_message_get_type (void) G_GNUC_CONST; - -MessagingMenuMessage * messaging_menu_message_new (const gchar *id, - GIcon *icon, - const gchar *title, - const gchar *subtitle, - const gchar *body, - gint64 time); - -const gchar * messaging_menu_message_get_id (MessagingMenuMessage *msg); - -GIcon * messaging_menu_message_get_icon (MessagingMenuMessage *msg); - -const gchar * messaging_menu_message_get_title (MessagingMenuMessage *msg); - -const gchar * messaging_menu_message_get_subtitle (MessagingMenuMessage *msg); - -const gchar * messaging_menu_message_get_body (MessagingMenuMessage *msg); - -gint64 messaging_menu_message_get_time (MessagingMenuMessage *msg); - -gboolean messaging_menu_message_get_draws_attention (MessagingMenuMessage *msg); - -void messaging_menu_message_set_draws_attention (MessagingMenuMessage *msg, - gboolean draws_attention); - -void messaging_menu_message_add_action (MessagingMenuMessage *msg, - const gchar *id, - const gchar *label, - const GVariantType *parameter_type, - GVariant *parameter_hint); - -G_END_DECLS - -#endif diff --git a/libmessaging-menu/messaging-menu-app.c b/libmessaging-menu/messaging-menu.c index 421a09f..467a67a 100644 --- a/libmessaging-menu/messaging-menu-app.c +++ b/libmessaging-menu/messaging-menu.c @@ -17,12 +17,10 @@ * Lars Uebernickel <lars.uebernickel@canonical.com> */ -#include "messaging-menu-app.h" +#include "messaging-menu.h" #include "indicator-messages-service.h" -#include "indicator-messages-application.h" #include <gio/gdesktopappinfo.h> -#include <string.h> /** * SECTION:messaging-menu @@ -104,14 +102,14 @@ struct _MessagingMenuApp int registered; /* -1 for unknown */ MessagingMenuStatus status; gboolean status_set; + GSimpleActionGroup *source_actions; + GMenu *menu; GDBusConnection *bus; - GHashTable *messages; - GList *sources; - IndicatorMessagesApplication *app_interface; - IndicatorMessagesService *messages_service; guint watch_id; + guint action_export_id; + guint menu_export_id; GCancellable *cancellable; }; @@ -135,61 +133,10 @@ static guint signals[N_SIGNALS]; static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" }; -typedef struct -{ - gchar *id; - GIcon *icon; - gchar *label; - - guint32 count; - gint64 time; - gchar *string; - gboolean draws_attention; -} Source; - static void global_status_changed (IndicatorMessagesService *service, const gchar *status_str, gpointer user_data); -/* in messaging-menu-message.c */ -GVariant * _messaging_menu_message_to_variant (MessagingMenuMessage *msg); - -static void -source_free (gpointer data) -{ - Source *source = data; - - if (source) - { - g_free (source->id); - g_clear_object (&source->icon); - g_free (source->label); - g_free (source->string); - g_slice_free (Source, source); - } -} - -static GVariant * -source_to_variant (Source *source) -{ - GVariant *v; - gchar *iconstr; - - iconstr = source->icon ? g_icon_to_string (source->icon) : NULL; - - v = g_variant_new ("(sssuxsb)", source->id, - source->label, - iconstr ? iconstr : "", - source->count, - source->time, - source->string ? source->string : "", - source->draws_attention); - - g_free (iconstr); - - return v; -} - static gchar * messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app) { @@ -208,14 +155,18 @@ messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app) } static void -messaging_menu_app_got_bus (GObject *source, - GAsyncResult *res, - gpointer user_data) +export_menus_and_actions (GObject *source, + GAsyncResult *res, + gpointer user_data) { MessagingMenuApp *app = user_data; GError *error = NULL; gchar *object_path; + object_path = messaging_menu_app_get_dbus_object_path (app); + if (!object_path) + return; + app->bus = g_bus_get_finish (res, &error); if (app->bus == NULL) { @@ -224,13 +175,23 @@ messaging_menu_app_got_bus (GObject *source, return; } - object_path = messaging_menu_app_get_dbus_object_path (app); + app->action_export_id = g_dbus_connection_export_action_group (app->bus, + object_path, + G_ACTION_GROUP (app->source_actions), + &error); + if (!app->action_export_id) + { + g_warning ("unable to export action group: %s", error->message); + g_clear_error (&error); + } - if (object_path && - !g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (app->app_interface), - app->bus, object_path, &error)) + app->menu_export_id = g_dbus_connection_export_menu_model (app->bus, + object_path, + G_MENU_MODEL (app->menu), + &error); + if (!app->menu_export_id) { - g_warning ("unable to export application interface: %s", error->message); + g_warning ("unable to export menu: %s", error->message); g_clear_error (&error); } @@ -253,7 +214,7 @@ messaging_menu_app_set_desktop_id (MessagingMenuApp *app, g_bus_get (G_BUS_TYPE_SESSION, app->cancellable, - messaging_menu_app_got_bus, + export_menus_and_actions, app); } @@ -287,6 +248,20 @@ messaging_menu_app_dispose (GObject *object) { MessagingMenuApp *app = MESSAGING_MENU_APP (object); + if (app->bus) + { + if (app->action_export_id > 0) + g_dbus_connection_unexport_action_group (app->bus, app->action_export_id); + + if (app->menu_export_id > 0) + g_dbus_connection_unexport_menu_model (app->bus, app->menu_export_id); + + app->action_export_id = 0; + app->menu_export_id = 0; + g_object_unref (app->bus); + app->bus = NULL; + } + if (app->watch_id > 0) { g_bus_unwatch_name (app->watch_id); @@ -312,14 +287,9 @@ messaging_menu_app_dispose (GObject *object) g_clear_object (&app->messages_service); } - g_clear_pointer (&app->messages, g_hash_table_unref); - - g_list_free_full (app->sources, source_free); - app->sources = NULL; - - g_clear_object (&app->app_interface); g_clear_object (&app->appinfo); - g_clear_object (&app->bus); + g_clear_object (&app->source_actions); + g_clear_object (&app->menu); G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object); } @@ -450,168 +420,6 @@ indicator_messages_vanished (GDBusConnection *bus, } } -static gboolean -messaging_menu_app_list_sources (IndicatorMessagesApplication *app_interface, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - GVariantBuilder builder; - GList *it; - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssuxsb)")); - - for (it = app->sources; it; it = it->next) - g_variant_builder_add_value (&builder, source_to_variant (it->data)); - - indicator_messages_application_complete_list_sources (app_interface, - invocation, - g_variant_builder_end (&builder)); - - return TRUE; -} - -static gint -compare_source_id (gconstpointer a, - gconstpointer b) -{ - const Source *source = a; - const gchar *id = b; - - return strcmp (source->id, id); -} - -static gboolean -messaging_menu_app_remove_source_internal (MessagingMenuApp *app, - const gchar *source_id) -{ - GList *node; - - node = g_list_find_custom (app->sources, source_id, compare_source_id); - if (node) - { - source_free (node->data); - app->sources = g_list_delete_link (app->sources, node); - return TRUE; - } - - return FALSE; -} - -static gboolean -messaging_menu_app_remove_message_internal (MessagingMenuApp *app, - const gchar *message_id) -{ - return g_hash_table_remove (app->messages, message_id); -} - -static gboolean -messaging_menu_app_activate_source (IndicatorMessagesApplication *app_interface, - GDBusMethodInvocation *invocation, - const gchar *source_id, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - GQuark q = g_quark_from_string (source_id); - - /* Activate implies removing the source, no need for SourceRemoved */ - if (messaging_menu_app_remove_source_internal (app, source_id)) - g_signal_emit (app, signals[ACTIVATE_SOURCE], q, source_id); - - indicator_messages_application_complete_activate_source (app_interface, invocation); - - return TRUE; -} - -static gboolean -messaging_menu_app_list_messages (IndicatorMessagesApplication *app_interface, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - GVariantBuilder builder; - GHashTableIter iter; - MessagingMenuMessage *message; - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssssxaa{sv}b)")); - - g_hash_table_iter_init (&iter, app->messages); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &message)) - g_variant_builder_add_value (&builder, _messaging_menu_message_to_variant (message)); - - indicator_messages_application_complete_list_messages (app_interface, - invocation, - g_variant_builder_end (&builder)); - - return TRUE; -} - -static gboolean -messaging_menu_app_activate_message (IndicatorMessagesApplication *app_interface, - GDBusMethodInvocation *invocation, - const gchar *message_id, - const gchar *action_id, - GVariant *params, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - MessagingMenuMessage *msg; - - msg = g_hash_table_lookup (app->messages, message_id); - if (msg) - { - if (*action_id) - { - gchar *signal; - - signal = g_strconcat ("activate::", action_id, NULL); - - if (g_variant_n_children (params)) - { - GVariant *param; - - g_variant_get_child (params, 0, "v", ¶m); - g_signal_emit_by_name (msg, signal, action_id, param); - - g_variant_unref (param); - } - else - g_signal_emit_by_name (msg, signal, action_id, NULL); - - g_free (signal); - } - else - g_signal_emit_by_name (msg, "activate", NULL, NULL); - - - /* Activate implies removing the message, no need for MessageRemoved */ - messaging_menu_app_remove_message_internal (app, message_id); - } - - indicator_messages_application_complete_activate_message (app_interface, invocation); - - return TRUE; -} - -static gboolean -messaging_menu_app_dismiss (IndicatorMessagesApplication *app_interface, - GDBusMethodInvocation *invocation, - const gchar * const *sources, - const gchar * const *messages, - gpointer user_data) -{ - MessagingMenuApp *app = user_data; - const gchar * const *it; - - for (it = sources; *it; it++) - messaging_menu_app_remove_source_internal (app, *it); - - for (it = messages; *it; it++) - messaging_menu_app_remove_message_internal (app, *it); - - return TRUE; -} - static void messaging_menu_app_init (MessagingMenuApp *app) { @@ -619,21 +427,15 @@ messaging_menu_app_init (MessagingMenuApp *app) app->status_set = FALSE; app->bus = NULL; + app->action_export_id = 0; + app->menu_export_id = 0; + app->cancellable = g_cancellable_new (); - app->app_interface = indicator_messages_application_skeleton_new (); - g_signal_connect (app->app_interface, "handle-list-sources", - G_CALLBACK (messaging_menu_app_list_sources), app); - g_signal_connect (app->app_interface, "handle-activate-source", - G_CALLBACK (messaging_menu_app_activate_source), app); - g_signal_connect (app->app_interface, "handle-list-messages", - G_CALLBACK (messaging_menu_app_list_messages), app); - g_signal_connect (app->app_interface, "handle-activate-message", - G_CALLBACK (messaging_menu_app_activate_message), app); - g_signal_connect (app->app_interface, "handle-dismiss", - G_CALLBACK (messaging_menu_app_dismiss), app); + app->source_actions = g_simple_action_group_new (); + app->menu = g_menu_new (); - app->messages = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + app->cancellable = g_cancellable_new (); app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, "com.canonical.indicator.messages", @@ -806,73 +608,124 @@ global_status_changed (IndicatorMessagesService *service, g_signal_emit (app, signals[STATUS_CHANGED], 0, status); } -static Source * -messaging_menu_app_lookup_source (MessagingMenuApp *app, - const gchar *id) +static void +source_action_activated (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + const gchar *name = g_action_get_name (G_ACTION (action)); + GQuark q = g_quark_from_string (name); + + messaging_menu_app_remove_source (app, name); + + g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name); +} + +static void +messaging_menu_app_insert_source_action (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + GVariant *state) { - GList *node; + GSimpleAction *action; + GMenuItem *menuitem; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (id != NULL); + + if (g_simple_action_group_lookup (app->source_actions, id)) + { + g_warning ("a source with id '%s' already exists", id); + return; + } - node = g_list_find_custom (app->sources, id, compare_source_id); + action = g_simple_action_new_stateful (id, NULL, state); + g_signal_connect (action, "activate", + G_CALLBACK (source_action_activated), app); + g_simple_action_group_insert (app->source_actions, G_ACTION (action)); + g_object_unref (action); - return node ? node->data : NULL; + menuitem = g_menu_item_new (label, NULL); + g_menu_item_set_action_and_target_value (menuitem, id, NULL); + g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem"); + if (icon) + { + gchar *iconstr = g_icon_to_string (icon); + g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr); + g_free (iconstr); + } + g_menu_insert_item (app->menu, position, menuitem); + g_object_unref (menuitem); } -static Source * -messaging_menu_app_get_source (MessagingMenuApp *app, - const gchar *id) +static GSimpleAction * +messaging_menu_app_get_source_action (MessagingMenuApp *app, + const gchar *source_id) + { - Source *source; + GAction *action; - source = messaging_menu_app_lookup_source (app, id); - if (!source) - g_warning ("a source with id '%s' doesn't exist", id); + g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL); + g_return_val_if_fail (source_id != NULL, NULL); - return source; + 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 G_SIMPLE_ACTION (action); } static void -messaging_menu_app_notify_source_changed (MessagingMenuApp *app, - Source *source) +messaging_menu_app_set_source_action (MessagingMenuApp *app, + const gchar *source_id, + guint count, + gint64 time, + const gchar *string) { - indicator_messages_application_emit_source_changed (app->app_interface, - source_to_variant (source)); + GSimpleAction *action; + GVariant *state; + gboolean draws_attention; + GVariant *new_state; + + action = messaging_menu_app_get_source_action (app, source_id); + if (!action) + return; + + state = g_action_get_state (G_ACTION (action)); + g_variant_get_child (state, 3, "b", &draws_attention); + + new_state = g_variant_new ("(uxsb)", count, time, string, draws_attention); + g_simple_action_set_state (action, new_state); + + g_variant_unref (state); } static void -messaging_menu_app_insert_source_internal (MessagingMenuApp *app, - gint position, - const gchar *id, - GIcon *icon, - const gchar *label, - guint count, - gint64 time, - const gchar *string) +messaging_menu_app_set_draws_attention (MessagingMenuApp *app, + const gchar *source_id, + gboolean draws_attention) { - Source *source; + GSimpleAction *action; + GVariant *state; + guint count; + gint64 time; + const gchar *string; + GVariant *new_state; - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (id != NULL); - g_return_if_fail (label != NULL); + action = messaging_menu_app_get_source_action (app, source_id); + if (!action) + return; - if (messaging_menu_app_lookup_source (app, id)) - { - g_warning ("a source with id '%s' already exists", id); - return; - } + state = g_action_get_state (G_ACTION (action)); + g_variant_get (state, "(ux&sb)", &count, &time, &string, NULL); - source = g_slice_new0 (Source); - source->id = g_strdup (id); - source->label = g_strdup (label); - if (icon) - source->icon = g_object_ref (icon); - source->count = count; - source->time = time; - source->string = g_strdup (string); - app->sources = g_list_insert (app->sources, source, position); - - indicator_messages_application_emit_source_added (app->app_interface, - position, - source_to_variant (source)); + new_state = g_variant_new ("(uxsb)", count, time, string, draws_attention); + g_simple_action_set_state (action, new_state); + + g_variant_unref (state); } /** @@ -949,7 +802,8 @@ messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, const gchar *label, guint count) { - messaging_menu_app_insert_source_internal (app, position, id, icon, label, count, 0, ""); + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxsb)", count, 0, "", FALSE)); } /** @@ -1003,7 +857,8 @@ messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, const gchar *label, gint64 time) { - messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, time, ""); + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxsb)", 0, time, "", FALSE)); } /** @@ -1059,7 +914,8 @@ messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, const gchar *label, const gchar *str) { - messaging_menu_app_insert_source_internal (app, position, id, icon, label, 0, 0, str); + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxsb)", 0, 0, str, FALSE)); } /** @@ -1099,11 +955,34 @@ void messaging_menu_app_remove_source (MessagingMenuApp *app, const gchar *source_id) { + int n_items; + int i; + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); g_return_if_fail (source_id != NULL); - if (messaging_menu_app_remove_source_internal (app, source_id)) - indicator_messages_application_emit_source_removed (app->app_interface, source_id); + if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL) + return; + + n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu)); + for (i = 0; i < n_items; i++) + { + gchar *action; + + if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i, + "action", "s", &action)) + { + if (!g_strcmp0 (action, source_id)) + { + g_menu_remove (app->menu, i); + break; + } + + g_free (action); + } + } + + g_simple_action_group_remove (app->source_actions, source_id); } /** @@ -1120,7 +999,46 @@ messaging_menu_app_has_source (MessagingMenuApp *app, g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE); g_return_val_if_fail (source_id != NULL, FALSE); - return messaging_menu_app_lookup_source (app, source_id) != NULL; + return g_simple_action_group_lookup (app->source_actions, source_id) != NULL; +} + +static GMenuItem * +g_menu_find_item_with_action (GMenu *menu, + const gchar *action, + gint *out_pos) +{ + gint i; + gint n_elements; + GMenuItem *item = NULL; + + n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu)); + + for (i = 0; i < n_elements && item == NULL; i++) + { + GVariant *attr; + + item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i); + attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING); + + if (!g_str_equal (action, g_variant_get_string (attr, NULL))) + g_clear_object (&item); + + g_variant_unref (attr); + } + + if (item && out_pos) + *out_pos = i - 1; + + return item; +} + +static void +g_menu_replace_item (GMenu *menu, + gint pos, + GMenuItem *item) +{ + g_menu_remove (menu, pos); + g_menu_insert_item (menu, pos, item); } /** @@ -1136,19 +1054,21 @@ messaging_menu_app_set_source_label (MessagingMenuApp *app, const gchar *source_id, const gchar *label) { - Source *source; + gint pos; + GMenuItem *item; g_return_if_fail (MESSAGING_MENU_IS_APP (app)); g_return_if_fail (source_id != NULL); g_return_if_fail (label != NULL); - source = messaging_menu_app_get_source (app, source_id); - if (source) - { - g_free (source->label); - source->label = g_strdup (label); - messaging_menu_app_notify_source_changed (app, source); - } + item = g_menu_find_item_with_action (app->menu, source_id, &pos); + if (item == NULL) + return; + + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label); + g_menu_replace_item (app->menu, pos, item); + + g_object_unref (item); } /** @@ -1164,19 +1084,33 @@ messaging_menu_app_set_source_icon (MessagingMenuApp *app, const gchar *source_id, GIcon *icon) { - Source *source; + gint pos; + GMenuItem *item; g_return_if_fail (MESSAGING_MENU_IS_APP (app)); g_return_if_fail (source_id != NULL); - source = messaging_menu_app_get_source (app, source_id); - if (source) + item = g_menu_find_item_with_action (app->menu, source_id, &pos); + if (item == NULL) + return; + + if (icon) + { + gchar *iconstr; + + iconstr = g_icon_to_string (icon); + g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); + + g_free (iconstr); + } + else { - g_clear_object (&source->icon); - if (icon) - source->icon = g_object_ref (icon); - messaging_menu_app_notify_source_changed (app, source); + g_menu_item_set_attribute_value (item, "x-canonical-icon", NULL); } + + g_menu_replace_item (app->menu, pos, item); + + g_object_unref (item); } /** @@ -1191,17 +1125,7 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app, const gchar *source_id, guint count) { - Source *source; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - source = messaging_menu_app_get_source (app, source_id); - if (source) - { - source->count = count; - messaging_menu_app_notify_source_changed (app, source); - } + messaging_menu_app_set_source_action (app, source_id, count, 0, ""); } /** @@ -1217,17 +1141,7 @@ messaging_menu_app_set_source_time (MessagingMenuApp *app, const gchar *source_id, gint64 time) { - Source *source; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - source = messaging_menu_app_get_source (app, source_id); - if (source) - { - source->time = time; - messaging_menu_app_notify_source_changed (app, source); - } + messaging_menu_app_set_source_action (app, source_id, 0, time, ""); } /** @@ -1243,18 +1157,7 @@ messaging_menu_app_set_source_string (MessagingMenuApp *app, const gchar *source_id, const gchar *str) { - Source *source; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - source = messaging_menu_app_get_source (app, source_id); - if (source) - { - g_free (source->string); - source->string = g_strdup (str); - messaging_menu_app_notify_source_changed (app, source); - } + messaging_menu_app_set_source_action (app, source_id, 0, 0, str); } /** @@ -1272,17 +1175,7 @@ void messaging_menu_app_draw_attention (MessagingMenuApp *app, const gchar *source_id) { - Source *source; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - source = messaging_menu_app_get_source (app, source_id); - if (source) - { - source->draws_attention = TRUE; - messaging_menu_app_notify_source_changed (app, source); - } + messaging_menu_app_set_draws_attention (app, source_id, TRUE); } /** @@ -1303,131 +1196,5 @@ void messaging_menu_app_remove_attention (MessagingMenuApp *app, const gchar *source_id) { - Source *source; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - source = messaging_menu_app_get_source (app, source_id); - if (source) - { - source->draws_attention = FALSE; - messaging_menu_app_notify_source_changed (app, source); - } -} - -/** - * messaging_menu_app_append_message: - * @app: a #MessagingMenuApp - * @msg: the #MessagingMenuMessage to append - * @source_id: (allow-none): the source id to which @msg is added, or NULL - * @notify: whether a notification bubble should be shown for this - * message - * - * Appends @msg to the source with id @source_id of @app. The messaging - * menu might not display this message immediately if other messages are - * queued before this one. - * - * If @source_id has a count associated with it, that count will be - * increased by one. - * - * If @source_id is %NULL, @msg won't be associated with a source. - */ -void -messaging_menu_app_append_message (MessagingMenuApp *app, - MessagingMenuMessage *msg, - const gchar *source_id, - gboolean notify) -{ - const gchar *id; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (MESSAGING_MENU_IS_MESSAGE (msg)); - - id = messaging_menu_message_get_id (msg); - - if (g_hash_table_lookup (app->messages, id)) - { - g_warning ("a message with id '%s' already exists", id); - return; - } - - g_hash_table_insert (app->messages, g_strdup (id), g_object_ref (msg)); - indicator_messages_application_emit_message_added (app->app_interface, - _messaging_menu_message_to_variant (msg)); - - if (source_id) - { - Source *source; - - source = messaging_menu_app_get_source (app, source_id); - if (source && source->count >= 0) - { - source->count++; - messaging_menu_app_notify_source_changed (app, source); - } - } -} - -/** - * messaging_menu_app_get_message: - * @app: a #MessagingMenuApp - * @id: id of the message to retrieve - * - * Retrieves the message with @id, that was added with - * messaging_menu_app_append_message(). - * - * Returns: (transfer none) (allow-none): the #MessagingMenuApp with - * @id, or %NULL - */ -MessagingMenuMessage * -messaging_menu_app_get_message (MessagingMenuApp *app, - const gchar *id) -{ - g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL); - g_return_val_if_fail (id != NULL, NULL); - - return g_hash_table_lookup (app->messages, id); -} - -/** - * messaging_menu_app_remove_message: - * @app: a #MessagingMenuApp - * @msg: the #MessagingMenuMessage to remove - * - * Removes @msg from @app. - * - * If @source_id has a count associated with it, that count will be - * decreased by one. - */ -void -messaging_menu_app_remove_message (MessagingMenuApp *app, - MessagingMenuMessage *msg) -{ - /* take a ref of @msg here to make sure the pointer returned by - * _get_id() is valid for the duration of remove_message_by_id. */ - g_object_ref (msg); - messaging_menu_app_remove_message_by_id (app, messaging_menu_message_get_id (msg)); - g_object_unref (msg); -} - -/** - * messaging_menu_app_remove_message_by_id: - * @app: a #MessagingMenuApp - * @id: the unique id of @msg - * - * Removes the message with the id @id from @app. - * - * If @source_id has a count associated with it, that count will be - * decreased by one. - */ -void -messaging_menu_app_remove_message_by_id (MessagingMenuApp *app, - const gchar *id) -{ - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (id != NULL); - - if (messaging_menu_app_remove_message_internal (app, id)) - indicator_messages_application_emit_message_removed (app->app_interface, id); + messaging_menu_app_set_draws_attention (app, source_id, FALSE); } diff --git a/libmessaging-menu/messaging-menu.h b/libmessaging-menu/messaging-menu.h index 929b229..6c405c7 100644 --- a/libmessaging-menu/messaging-menu.h +++ b/libmessaging-menu/messaging-menu.h @@ -20,6 +20,129 @@ #ifndef __messaging_menu_h__ #define __messaging_menu_h__ -#include "messaging-menu-app.h" +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type() +#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp)) +#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass)) +#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP)) + +/** + * MessagingMenuStatus: + * @MESSAGING_MENU_STATUS_AVAILABLE: available + * @MESSAGING_MENU_STATUS_AWAY: away + * @MESSAGING_MENU_STATUS_BUSY: busy + * @MESSAGING_MENU_STATUS_INVISIBLE: invisible + * @MESSAGING_MENU_STATUS_OFFLINE: offline + * + * An enumeration for the possible chat statuses the messaging menu can be in. + */ +typedef enum { + MESSAGING_MENU_STATUS_AVAILABLE, + MESSAGING_MENU_STATUS_AWAY, + MESSAGING_MENU_STATUS_BUSY, + MESSAGING_MENU_STATUS_INVISIBLE, + MESSAGING_MENU_STATUS_OFFLINE +} MessagingMenuStatus; + + +typedef GObjectClass MessagingMenuAppClass; +typedef struct _MessagingMenuApp MessagingMenuApp; + +GType messaging_menu_app_get_type (void) G_GNUC_CONST; + +MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id); + +void messaging_menu_app_register (MessagingMenuApp *app); +void messaging_menu_app_unregister (MessagingMenuApp *app); + +void messaging_menu_app_set_status (MessagingMenuApp *app, + MessagingMenuStatus status); + +void messaging_menu_app_insert_source (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label); + +void messaging_menu_app_append_source (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label); + +void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count); + +void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count); + +void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time); + +void messaging_menu_app_append_source_with_time (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time); + +void messaging_menu_app_append_source_with_string (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str); + +void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str); + +void messaging_menu_app_remove_source (MessagingMenuApp *app, + const gchar *source_id); + +gboolean messaging_menu_app_has_source (MessagingMenuApp *app, + const gchar *source_id); + +void messaging_menu_app_set_source_label (MessagingMenuApp *app, + const gchar *source_id, + const gchar *label); + +void messaging_menu_app_set_source_icon (MessagingMenuApp *app, + const gchar *source_id, + GIcon *icon); + +void messaging_menu_app_set_source_count (MessagingMenuApp *app, + const gchar *source_id, + guint count); + +void messaging_menu_app_set_source_time (MessagingMenuApp *app, + const gchar *source_id, + gint64 time); + +void messaging_menu_app_set_source_string (MessagingMenuApp *app, + const gchar *source_id, + const gchar *str); + +void messaging_menu_app_draw_attention (MessagingMenuApp *app, + const gchar *source_id); + +void messaging_menu_app_remove_attention (MessagingMenuApp *app, + const gchar *source_id); + +G_END_DECLS #endif |