From 6f990698f610eb444845f36a70cad04bca2415f3 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 20 Nov 2012 15:45:03 +0100 Subject: messages-serivce: move menu creation into separate class --- src/Makefile.am | 4 +- src/im-phone-menu.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ src/im-phone-menu.h | 67 +++++++++++++++ src/messages-service.c | 81 ++++++++----------- 4 files changed, 319 insertions(+), 49 deletions(-) create mode 100644 src/im-phone-menu.c create mode 100644 src/im-phone-menu.h diff --git a/src/Makefile.am b/src/Makefile.am index a7bfe66..12c8031 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,9 @@ indicator_messages_service_SOURCES = \ gsettingsstrv.c \ gsettingsstrv.h \ gmenuutils.c \ - gmenuutils.h + gmenuutils.h \ + im-phone-menu.c \ + im-phone-menu.h indicator_messages_service_CFLAGS = \ $(APPLET_CFLAGS) \ diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c new file mode 100644 index 0000000..abb3a11 --- /dev/null +++ b/src/im-phone-menu.c @@ -0,0 +1,216 @@ +/* + * 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 "im-phone-menu.h" + +#include + +typedef GObjectClass ImPhoneMenuClass; + +struct _ImPhoneMenu +{ + GObject parent; + + GMenu *toplevel_menu; + GMenu *message_section; + GMenu *source_section; + +}; + +G_DEFINE_TYPE (ImPhoneMenu, im_phone_menu, G_TYPE_OBJECT); + +typedef void (*ImMenuForeachFunc) (GMenuModel *menu, gint pos); + +static void +im_phone_menu_foreach_item_with_action (GMenuModel *menu, + const gchar *action, + ImMenuForeachFunc func) +{ + gint n_items; + gint i; + + n_items = g_menu_model_get_n_items (menu); + for (i = 0; i < n_items; i++) + { + gchar *item_action; + + g_menu_model_get_item_attribute (menu, i, G_MENU_ATTRIBUTE_ACTION, "s", &item_action); + + if (g_str_equal (action, item_action)) + func (menu, i); + + g_free (item_action); + } +} + +static void +im_phone_menu_dispose (GObject *object) +{ + ImPhoneMenu *menu = IM_PHONE_MENU (object); + + g_clear_object (&menu->toplevel_menu); + g_clear_object (&menu->message_section); + g_clear_object (&menu->source_section); + + G_OBJECT_CLASS (im_phone_menu_parent_class)->dispose (object); +} + +static void +im_phone_menu_finalize (GObject *object) +{ + G_OBJECT_CLASS (im_phone_menu_parent_class)->finalize (object); +} + +static void +im_phone_menu_class_init (ImPhoneMenuClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = im_phone_menu_dispose; + object_class->finalize = im_phone_menu_finalize; +} + +static void +im_phone_menu_init (ImPhoneMenu *menu) +{ + menu->message_section = g_menu_new (); + menu->source_section = g_menu_new (); + + menu->toplevel_menu = g_menu_new (); + g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->message_section)); + g_menu_append_section (menu->toplevel_menu, NULL, G_MENU_MODEL (menu->source_section)); +} + +ImPhoneMenu * +im_phone_menu_new (void) +{ + return g_object_new (IM_TYPE_PHONE_MENU, NULL); +} + +GMenuModel * +im_phone_menu_get_model (ImPhoneMenu *menu) +{ + g_return_val_if_fail (IM_IS_PHONE_MENU (menu), NULL); + + return G_MENU_MODEL (menu->toplevel_menu); +} + +void +im_phone_menu_add_message (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id, + const gchar *iconstr, + const gchar *title, + const gchar *subtitle, + const gchar *body, + gint64 time) +{ + const gchar *app_id; + GMenuItem *item; + gchar *action_name; + + g_return_if_fail (IM_IS_PHONE_MENU (menu)); + g_return_if_fail (G_IS_DESKTOP_APP_INFO (app)); + + app_id = g_app_info_get_id (G_APP_INFO (app)); + g_return_if_fail (app_id); + + action_name = g_strconcat (app_id, ".", id, NULL); + + item = g_menu_item_new (title, action_name); + g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.messageitem"); + g_menu_item_set_attribute (item, "x-canonical-message-id", "s", id); + g_menu_item_set_attribute (item, "x-canonical-subtitle", "s", subtitle); + g_menu_item_set_attribute (item, "x-canonical-text", "s", body); + g_menu_item_set_attribute (item, "x-canonical-time", "x", time); + + if (iconstr) + g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); + + g_menu_append_item (menu->message_section, item); + + g_free (action_name); + g_object_unref (item); +} + +void +im_phone_menu_remove_message (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id) +{ + gchar *action_name; + + g_return_if_fail (IM_IS_PHONE_MENU (menu)); + g_return_if_fail (G_IS_DESKTOP_APP_INFO (app)); + + action_name = g_strconcat (g_app_info_get_id (G_APP_INFO (app)), ".", id, NULL); + im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->message_section), + action_name, + (ImMenuForeachFunc) g_menu_remove); + + g_free (action_name); +} + +void +im_phone_menu_add_source (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id, + const gchar *label, + const gchar *iconstr, + guint32 count, + gint64 time, + const gchar *string) +{ + GMenuItem *item; + gchar *action_name; + + g_return_if_fail (IM_IS_PHONE_MENU (menu)); + g_return_if_fail (G_IS_DESKTOP_APP_INFO (app)); + + action_name = g_strconcat (g_app_info_get_id (G_APP_INFO (app)), ".", id, NULL); + + item = g_menu_item_new (label, action_name); + g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.sourceitem"); + + if (iconstr) + g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); + + g_menu_append_item (menu->source_section, item); + + g_free (action_name); + g_object_unref (item); +} + +void +im_phone_menu_remove_source (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id) +{ + gchar *action_name; + + g_return_if_fail (IM_IS_PHONE_MENU (menu)); + g_return_if_fail (G_IS_DESKTOP_APP_INFO (app)); + + action_name = g_strconcat (g_app_info_get_id (G_APP_INFO (app)), ".", id, NULL); + im_phone_menu_foreach_item_with_action (G_MENU_MODEL (menu->source_section), + action_name, + (ImMenuForeachFunc) g_menu_remove); + + g_free (action_name); +} diff --git a/src/im-phone-menu.h b/src/im-phone-menu.h new file mode 100644 index 0000000..f7cc645 --- /dev/null +++ b/src/im-phone-menu.h @@ -0,0 +1,67 @@ +/* + * 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 __IM_PHONE_MENU_H__ +#define __IM_PHONE_MENU_H__ + +#include +#include + +#define IM_TYPE_PHONE_MENU (im_phone_menu_get_type ()) +#define IM_PHONE_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_PHONE_MENU, ImPhoneMenu)) +#define IM_PHONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_PHONE_MENU, ImPhoneMenuClass)) +#define IM_IS_PHONE_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_PHONE_MENU)) +#define IM_IS_PHONE_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_PHONE_MENU)) +#define IM_PHONE_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_PHONE_MENU, ImPhoneMenuClass)) + +typedef struct _ImPhoneMenu ImPhoneMenu; + +GType im_phone_menu_get_type (void); + +ImPhoneMenu * im_phone_menu_new (void); + +GMenuModel * im_phone_menu_get_model (ImPhoneMenu *menu); + +void im_phone_menu_add_message (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id, + const gchar *iconstr, + const gchar *title, + const gchar *subtitle, + const gchar *body, + gint64 time); + +void im_phone_menu_remove_message (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id); + +void im_phone_menu_add_source (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id, + const gchar *label, + const gchar *iconstr, + guint32 count, + gint64 time, + const gchar *string); + +void im_phone_menu_remove_source (ImPhoneMenu *menu, + GDesktopAppInfo *app, + const gchar *id); + +#endif diff --git a/src/messages-service.c b/src/messages-service.c index 81b7f0b..9cd7298 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -34,6 +34,7 @@ with this program. If not, see . #include "gmenuutils.h" #include "indicator-messages-service.h" #include "indicator-messages-application.h" +#include "im-phone-menu.h" #define NUM_STATUSES 5 @@ -43,9 +44,7 @@ static IndicatorMessagesService *messages_service; static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; static GMenu *toplevel_menu; -static GMenu *menu; -static GMenu *messages_section; -static GMenu *sources_section; +static ImPhoneMenu *menu; static GSettings *settings; static gboolean draws_attention; static const gchar *global_status[6]; /* max 5: available, away, busy, invisible, offline */ @@ -117,7 +116,7 @@ sources_listed (GObject *source_object, GAsyncResult *result, gpointer user_data) { - gchar *app_id = user_data; + GDesktopAppInfo *app = user_data; GVariant *sources; GVariantIter iter; const gchar *id; @@ -134,7 +133,7 @@ sources_listed (GObject *source_object, { g_warning ("could not fetch the list of sources: %s", error->message); g_error_free (error); - g_free (app_id); + g_object_unref (app); return; } @@ -142,30 +141,21 @@ sources_listed (GObject *source_object, while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr, &count, &time, &string, &draws_attention)) { - GMenuItem *item; GActionGroup *app_actions; GSimpleAction *action; - gchar *action_name; - app_actions = g_action_muxer_get_group (action_muxer, app_id); + app_actions = g_action_muxer_get_group (action_muxer, g_app_info_get_id (G_APP_INFO (app))); g_assert (app_actions); action = g_simple_action_new_stateful (id, NULL, g_variant_new_uint32 (count)); g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (app_actions), G_ACTION (action)); - action_name = g_strconcat (app_id, ".", id, NULL); - item = g_menu_item_new (label, action_name); - g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.sourceitem"); - if (iconstr && *iconstr) - g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); - g_menu_append_item (sources_section, item); + im_phone_menu_add_source (menu, app, id, label, iconstr, count, time, string); g_object_unref (action); - g_free (action_name); - g_object_unref (item); } g_variant_unref (sources); - g_free (app_id); + g_object_unref (app); } static void @@ -173,7 +163,7 @@ messages_listed (GObject *source_object, GAsyncResult *result, gpointer user_data) { - gchar *app_id = user_data; + GDesktopAppInfo *app = user_data; GVariant *messages; GError *error = NULL; GVariantIter iter; @@ -190,7 +180,7 @@ messages_listed (GObject *source_object, { g_warning ("could not fetch the list of messages: %s", error->message); g_error_free (error); - g_free (app_id); + g_object_unref (app); return; } @@ -198,34 +188,21 @@ messages_listed (GObject *source_object, while (g_variant_iter_next (&iter, "(&s&s&s&s&sxb)", &id, &iconstr, &title, &subtitle, &body, &time, &draws_attention)) { - GMenuItem *item; GActionGroup *app_actions; GSimpleAction *action; - gchar *action_name; - app_actions = g_action_muxer_get_group (action_muxer, app_id); + app_actions = g_action_muxer_get_group (action_muxer, g_app_info_get_id (G_APP_INFO (app))); g_assert (app_actions); action = g_simple_action_new (id, NULL); g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (app_actions), G_ACTION (action)); - action_name = g_strconcat (app_id, ".", id, NULL); - item = g_menu_item_new (title, action_name); - g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.messageitem"); - g_menu_item_set_attribute (item, "x-canonical-message-id", "s", id); - g_menu_item_set_attribute (item, "x-canonical-subtitle", "s", subtitle); - g_menu_item_set_attribute (item, "x-canonical-text", "s", body); - g_menu_item_set_attribute (item, "x-canonical-time", "x", time); - if (iconstr && *iconstr) - g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); - g_menu_append_item (messages_section, item); + im_phone_menu_add_message (menu, app, id, iconstr, title, subtitle, body, time); g_object_unref (action); - g_free (action_name); - g_object_unref (item); } g_variant_unref (messages); - g_free (app_id); + g_object_unref (app); } static void @@ -233,7 +210,7 @@ app_proxy_created (GObject *source_object, GAsyncResult *result, gpointer user_data) { - gchar *desktop_id = user_data; + GDesktopAppInfo *app = user_data; IndicatorMessagesApplication *app_proxy; GError *error = NULL; @@ -244,11 +221,12 @@ app_proxy_created (GObject *source_object, return; } - /* hash table takes ownership of desktop_id and app_proxy */ - g_hash_table_insert (applications, desktop_id, app_proxy); + g_hash_table_insert (applications, (gpointer) g_app_info_get_id (G_APP_INFO (app)), app_proxy); - indicator_messages_application_call_list_sources (app_proxy, NULL, sources_listed, g_strdup (desktop_id)); - indicator_messages_application_call_list_messages (app_proxy, NULL, messages_listed, g_strdup (desktop_id)); + indicator_messages_application_call_list_sources (app_proxy, NULL, sources_listed, g_object_ref (app)); + indicator_messages_application_call_list_messages (app_proxy, NULL, messages_listed, g_object_ref (app)); + + g_object_unref (app); } static void @@ -261,6 +239,7 @@ register_application (IndicatorMessagesService *service, GDBusConnection *bus; const gchar *sender; GSimpleActionGroup *app_actions; + GDesktopAppInfo *app; if (g_hash_table_lookup (applications, desktop_id)) { g_warning ("application with id '%s' already exists", desktop_id); @@ -270,12 +249,21 @@ register_application (IndicatorMessagesService *service, return; } + app = g_desktop_app_info_new (desktop_id); + if (!app) { + g_warning ("application with id '%s' already exists", desktop_id); + g_dbus_method_invocation_return_dbus_error (invocation, + "com.canonical.indicator.messages.UnknownApplication", + "an application with the given id doesn't exist"); + return; + } + bus = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (service)); sender = g_dbus_method_invocation_get_sender (invocation); indicator_messages_application_proxy_new (bus, G_DBUS_PROXY_FLAGS_NONE, sender, menu_path, NULL, - app_proxy_created, g_strdup (desktop_id)); + app_proxy_created, g_object_ref (app)); app_actions = g_simple_action_group_new (); g_action_muxer_insert (action_muxer, desktop_id, G_ACTION_GROUP (app_actions)); @@ -285,6 +273,7 @@ register_application (IndicatorMessagesService *service, indicator_messages_service_complete_register_application (service, invocation); g_object_unref (app_actions); + g_object_unref (app); } static void @@ -361,7 +350,7 @@ got_bus (GObject *object, } g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT "/phone", - G_MENU_MODEL (menu), &error); + im_phone_menu_get_model (menu), &error); if (error) { g_warning ("unable to export menu on dbus: %s", error->message); g_error_free (error); @@ -416,14 +405,10 @@ main (int argc, char ** argv) g_signal_connect (messages_service, "handle-unregister-application", G_CALLBACK (unregister_application), NULL); - menu = g_menu_new (); - sources_section = g_menu_new (); - messages_section = g_menu_new (); - g_menu_append_section (menu, NULL, G_MENU_MODEL (sources_section)); - g_menu_append_section (menu, NULL, G_MENU_MODEL (messages_section)); + menu = im_phone_menu_new (); toplevel_menu = g_menu_new (); - g_menu_append_submenu (toplevel_menu, NULL, G_MENU_MODEL (menu)); + g_menu_append_submenu (toplevel_menu, NULL, im_phone_menu_get_model (menu)); settings = g_settings_new ("com.canonical.indicator.messages"); -- cgit v1.2.3