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 From 2021da310c84d28efcf9bb359b7a8f7065743267 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 20 Nov 2012 22:20:23 +0100 Subject: messages-service: move app handling into separate class Add ImApplicationList, a class that manages the list of applictions that are currently registered with the messaging menu. It creates dbus proxies for running applications and sends signals when the app adds messages or sources. --- src/Makefile.am | 4 +- src/im-application-list.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++ src/im-application-list.h | 52 +++++++ src/messages-service.c | 176 +++-------------------- 4 files changed, 419 insertions(+), 161 deletions(-) create mode 100644 src/im-application-list.c create mode 100644 src/im-application-list.h diff --git a/src/Makefile.am b/src/Makefile.am index 12c8031..5d8bad8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,7 +54,9 @@ indicator_messages_service_SOURCES = \ gmenuutils.c \ gmenuutils.h \ im-phone-menu.c \ - im-phone-menu.h + im-phone-menu.h \ + im-application-list.c \ + im-application-list.h indicator_messages_service_CFLAGS = \ $(APPLET_CFLAGS) \ diff --git a/src/im-application-list.c b/src/im-application-list.c new file mode 100644 index 0000000..33f06ab --- /dev/null +++ b/src/im-application-list.c @@ -0,0 +1,348 @@ +/* + * 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-application-list.h" + +#include "indicator-messages-application.h" +#include "gactionmuxer.h" + +#include + +typedef GObjectClass ImApplicationListClass; + +struct _ImApplicationList +{ + GObject parent; + + GHashTable *applications; + GActionMuxer *muxer; +}; + +G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT); + +enum +{ + SOURCE_ADDED, + MESSAGE_ADDED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + +typedef struct +{ + ImApplicationList *list; + GDesktopAppInfo *info; + IndicatorMessagesApplication *proxy; + GSimpleActionGroup *actions; + GCancellable *cancellable; +} Application; + +static void +application_free (gpointer data) +{ + Application *app = data; + + if (!app) + return; + + g_clear_object (&app->info); + + if (app->cancellable) + { + g_cancellable_cancel (app->cancellable); + g_clear_object (&app->cancellable); + } + + if (app->proxy) + g_object_unref (app->proxy); + + if (app->actions) + g_object_unref (app->actions); + + g_slice_free (Application, app); +} + +static void +im_application_list_dispose (GObject *object) +{ + ImApplicationList *list = IM_APPLICATION_LIST (object); + + g_clear_pointer (&list->applications, g_hash_table_unref); + g_clear_object (&list->muxer); + + G_OBJECT_CLASS (im_application_list_parent_class)->dispose (object); +} + +static void +im_application_list_finalize (GObject *object) +{ + G_OBJECT_CLASS (im_application_list_parent_class)->finalize (object); +} + +static void +im_application_list_class_init (ImApplicationListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = im_application_list_dispose; + object_class->finalize = im_application_list_finalize; + + signals[SOURCE_ADDED] = g_signal_new ("source-added", + IM_TYPE_APPLICATION_LIST, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 8, + G_TYPE_DESKTOP_APP_INFO, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_UINT, + G_TYPE_INT64, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + + signals[MESSAGE_ADDED] = g_signal_new ("message-added", + IM_TYPE_APPLICATION_LIST, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 8, + G_TYPE_DESKTOP_APP_INFO, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INT64, + G_TYPE_BOOLEAN); +} + +static void +im_application_list_init (ImApplicationList *list) +{ + list->applications = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, application_free); + list->muxer = g_action_muxer_new (); +} + +ImApplicationList * +im_application_list_new (void) +{ + return g_object_new (IM_TYPE_APPLICATION_LIST, NULL); +} + +gboolean +im_application_list_add (ImApplicationList *list, + const gchar *desktop_id) +{ + GDesktopAppInfo *info; + Application *app; + const gchar *id; + + g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), FALSE); + g_return_val_if_fail (desktop_id != NULL, FALSE); + + if (g_hash_table_contains (list->applications, desktop_id)) + { + g_warning ("an application with id '%s' already exists", desktop_id); + return FALSE; + } + + info = g_desktop_app_info_new (desktop_id); + if (!info) + { + g_warning ("application with id '%s' already exists", desktop_id); + return FALSE; + } + + id = g_app_info_get_id (G_APP_INFO (info)); + + app = g_slice_new0 (Application); + app->list = list; + app->info = info; + app->actions = g_simple_action_group_new (); + + g_hash_table_insert (list->applications, (gpointer) id, app); + g_action_muxer_insert (list->muxer, id, G_ACTION_GROUP (app->actions)); + + return TRUE; +} + +void +im_application_list_remove (ImApplicationList *list, + const gchar *id) +{ + g_return_if_fail (IM_IS_APPLICATION_LIST (list)); + + g_hash_table_remove (list->applications, id); + g_action_muxer_remove (list->muxer, id); +} + +static void +im_application_list_sources_listed (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + Application *app = user_data; + GVariant *sources; + GError *error = NULL; + + if (indicator_messages_application_call_list_sources_finish (app->proxy, &sources, result, &error)) + { + GVariantIter iter; + const gchar *id; + const gchar *label; + const gchar *iconstr; + guint32 count; + gint64 time; + const gchar *string; + gboolean draws_attention; + + g_variant_iter_init (&iter, sources); + while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr, &count, + &time, &string, &draws_attention)) + { + GSimpleAction *action; + + action = g_simple_action_new_stateful (id, NULL, g_variant_new_uint32 (count)); + g_simple_action_group_insert (app->actions, G_ACTION (action)); + + g_signal_emit (app->list, signals[SOURCE_ADDED], 0, + app->info, id, label, iconstr, count, time, string, draws_attention); + + g_object_unref (action); + } + g_variant_unref (sources); + } + else + { + g_warning ("could not fetch the list of sources: %s", error->message); + g_error_free (error); + } +} + +static void +im_application_list_messages_listed (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + Application *app = user_data; + GVariant *messages; + GError *error = NULL; + + if (indicator_messages_application_call_list_messages_finish (app->proxy, &messages, result, &error)) + { + GVariantIter iter; + const gchar *id; + const gchar *iconstr; + const gchar *title; + const gchar *subtitle; + const gchar *body; + gint64 time; + gboolean draws_attention; + + g_variant_iter_init (&iter, messages); + while (g_variant_iter_next (&iter, "(&s&s&s&s&sxb)", &id, &iconstr, &title, &subtitle, &body, + &time, &draws_attention)) + { + GSimpleAction *action; + + action = g_simple_action_new (id, NULL); + g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (app->actions), G_ACTION (action)); + + g_signal_emit (app->list, signals[MESSAGE_ADDED], 0, + app->info, id, iconstr, title, subtitle, body, time, draws_attention); + + g_object_unref (action); + } + + g_variant_unref (messages); + } + else + { + g_warning ("could not fetch the list of messages: %s", error->message); + g_error_free (error); + } +} + +static void +im_application_list_proxy_created (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + Application *app = user_data; + GError *error = NULL; + + app->proxy = indicator_messages_application_proxy_new_finish (result, &error); + if (!app) + { + g_warning ("could not create application proxy: %s", error->message); + g_error_free (error); + return; + } + + indicator_messages_application_call_list_sources (app->proxy, app->cancellable, + im_application_list_sources_listed, app); + indicator_messages_application_call_list_messages (app->proxy, app->cancellable, + im_application_list_messages_listed, app); +} + +void +im_application_list_set_remote (ImApplicationList *list, + const gchar *id, + GDBusConnection *connection, + const gchar *unique_bus_name, + const gchar *object_path) +{ + Application *app; + + g_return_if_fail (IM_IS_APPLICATION_LIST (list)); + + app = g_hash_table_lookup (list->applications, id); + if (!app) + { + g_warning ("'%s' is not a registered appliction", id); + return; + } + + if (app->proxy || app->cancellable) + { + g_warning ("application '%s' is already running on '%s'", + id, g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy))); + return; + } + + app->cancellable = g_cancellable_new (); + indicator_messages_application_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE, + unique_bus_name, object_path, app->cancellable, + im_application_list_proxy_created, app); +} + +GActionGroup * +im_application_list_get_action_group (ImApplicationList *list) +{ + g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL); + + return G_ACTION_GROUP (list->muxer); +} diff --git a/src/im-application-list.h b/src/im-application-list.h new file mode 100644 index 0000000..3bf21c9 --- /dev/null +++ b/src/im-application-list.h @@ -0,0 +1,52 @@ +/* + * 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_APPLICATION_LIST_H__ +#define __IM_APPLICATION_LIST_H__ + +#include + +#define IM_TYPE_APPLICATION_LIST (im_application_list_get_type ()) +#define IM_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationList)) +#define IM_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_APPLICATION_LIST, ImApplicationListClass)) +#define IM_IS_APPLICATION_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_APPLICATION_LIST)) +#define IM_IS_APPLICATION_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_APPLICATION_LIST)) +#define IM_APPLICATION_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_APPLICATION_LIST, ImApplicationListClass)) + +typedef struct _ImApplicationList ImApplicationList; + +GType im_application_list_get_type (void); + +ImApplicationList * im_application_list_new (void); + +gboolean im_application_list_add (ImApplicationList *list, + const gchar *desktop_id); + +void im_application_list_remove (ImApplicationList *list, + const gchar *id); + +void im_application_list_set_remote (ImApplicationList *list, + const gchar *id, + GDBusConnection *connection, + const gchar *unique_bus_name, + const gchar *object_path); + +GActionGroup * im_application_list_get_action_group (ImApplicationList *list); + +#endif diff --git a/src/messages-service.c b/src/messages-service.c index 9cd7298..a65e2d8 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -25,24 +25,22 @@ with this program. If not, see . #include #include #include -#include #include #include "dbus-data.h" -#include "gactionmuxer.h" #include "gsettingsstrv.h" #include "gmenuutils.h" #include "indicator-messages-service.h" #include "indicator-messages-application.h" #include "im-phone-menu.h" +#include "im-application-list.h" #define NUM_STATUSES 5 -static GHashTable *applications; +static ImApplicationList *applications; static IndicatorMessagesService *messages_service; static GSimpleActionGroup *actions; -static GActionMuxer *action_muxer; static GMenu *toplevel_menu; static ImPhoneMenu *menu; static GSettings *settings; @@ -111,124 +109,6 @@ status_action_activate (GSimpleAction *action, indicator_messages_service_emit_status_changed (messages_service, status); } -static void -sources_listed (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GDesktopAppInfo *app = user_data; - GVariant *sources; - GVariantIter iter; - const gchar *id; - const gchar *label; - const gchar *iconstr; - guint32 count; - gint64 time; - const gchar *string; - gboolean draws_attention; - GError *error = NULL; - - if (!indicator_messages_application_call_list_sources_finish (INDICATOR_MESSAGES_APPLICATION (source_object), - &sources, result, &error)) - { - g_warning ("could not fetch the list of sources: %s", error->message); - g_error_free (error); - g_object_unref (app); - return; - } - - g_variant_iter_init (&iter, sources); - while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr, &count, - &time, &string, &draws_attention)) - { - GActionGroup *app_actions; - GSimpleAction *action; - - 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)); - - im_phone_menu_add_source (menu, app, id, label, iconstr, count, time, string); - - g_object_unref (action); - } - - g_variant_unref (sources); - g_object_unref (app); -} - -static void -messages_listed (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GDesktopAppInfo *app = user_data; - GVariant *messages; - GError *error = NULL; - GVariantIter iter; - const gchar *id; - const gchar *iconstr; - const gchar *title; - const gchar *subtitle; - const gchar *body; - gint64 time; - gboolean draws_attention; - - if (!indicator_messages_application_call_list_messages_finish (INDICATOR_MESSAGES_APPLICATION (source_object), - &messages, result, &error)) - { - g_warning ("could not fetch the list of messages: %s", error->message); - g_error_free (error); - g_object_unref (app); - return; - } - - g_variant_iter_init (&iter, messages); - while (g_variant_iter_next (&iter, "(&s&s&s&s&sxb)", &id, &iconstr, &title, &subtitle, &body, - &time, &draws_attention)) - { - GActionGroup *app_actions; - GSimpleAction *action; - - 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)); - - im_phone_menu_add_message (menu, app, id, iconstr, title, subtitle, body, time); - - g_object_unref (action); - } - - g_variant_unref (messages); - g_object_unref (app); -} - -static void -app_proxy_created (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GDesktopAppInfo *app = user_data; - IndicatorMessagesApplication *app_proxy; - GError *error = NULL; - - app_proxy = indicator_messages_application_proxy_new_finish (result, &error); - if (!app_proxy) { - g_warning ("could not create application proxy: %s", error->message); - g_error_free (error); - return; - } - - 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_object_ref (app)); - indicator_messages_application_call_list_messages (app_proxy, NULL, messages_listed, g_object_ref (app)); - - g_object_unref (app); -} - static void register_application (IndicatorMessagesService *service, GDBusMethodInvocation *invocation, @@ -238,42 +118,21 @@ 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); - g_dbus_method_invocation_return_dbus_error (invocation, - "com.canonical.indicator.messages.ApplicationAlreadyRegistered", - "another application is already registered with this id"); - return; - } - app = g_desktop_app_info_new (desktop_id); - if (!app) { - g_warning ("application with id '%s' already exists", desktop_id); + if (!im_application_list_add (applications, desktop_id)) { g_dbus_method_invocation_return_dbus_error (invocation, - "com.canonical.indicator.messages.UnknownApplication", - "an application with the given id doesn't exist"); + "com.canonical.indicator.messages.RegistrationFailed", + "registration failed"); 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_object_ref (app)); - - app_actions = g_simple_action_group_new (); - g_action_muxer_insert (action_muxer, desktop_id, G_ACTION_GROUP (app_actions)); - + im_application_list_set_remote (applications, desktop_id, bus, sender, menu_path); g_settings_strv_append_unique (settings, "applications", desktop_id); indicator_messages_service_complete_register_application (service, invocation); - - g_object_unref (app_actions); - g_object_unref (app); } static void @@ -282,13 +141,8 @@ unregister_application (IndicatorMessagesService *service, const gchar *desktop_id, gpointer user_data) { - if (g_hash_table_remove (applications, desktop_id)) { - - /* TODO remove menu items that refer to this application */ - g_action_muxer_remove (action_muxer, desktop_id); - - g_settings_strv_remove (settings, "applications", desktop_id); - } + im_application_list_remove (applications, desktop_id); + g_settings_strv_remove (settings, "applications", desktop_id); indicator_messages_service_complete_unregister_application (service, invocation); } @@ -342,7 +196,8 @@ got_bus (GObject *object, } g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, - G_ACTION_GROUP (action_muxer), &error); + im_application_list_get_action_group (applications), + &error); if (error) { g_warning ("unable to export action group on dbus: %s", error->message); g_error_free (error); @@ -397,9 +252,6 @@ main (int argc, char ** argv) actions = create_action_group (); - action_muxer = g_action_muxer_new (); - g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); - g_signal_connect (messages_service, "handle-register-application", G_CALLBACK (register_application), NULL); g_signal_connect (messages_service, "handle-unregister-application", @@ -412,13 +264,17 @@ main (int argc, char ** argv) settings = g_settings_new ("com.canonical.indicator.messages"); - applications = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + applications = im_application_list_new (); + g_signal_connect_swapped (applications, "source-added", + G_CALLBACK (im_phone_menu_add_source), menu); + g_signal_connect_swapped (applications, "message-added", + G_CALLBACK (im_phone_menu_add_message), menu); g_main_loop_run(mainloop); /* Clean up */ g_object_unref (messages_service); g_object_unref (settings); - g_hash_table_unref (applications); + g_object_unref (applications); return 0; } -- cgit v1.2.3 From 717f9be0d9319ed4aa680c77aa2a30318da10fda Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 20 Nov 2012 23:14:48 +0100 Subject: ImApplicationList: listen for added and removed signals --- src/im-application-list.c | 185 +++++++++++++++++++++++++++++++++++++--------- src/messages-service.c | 4 + 2 files changed, 153 insertions(+), 36 deletions(-) diff --git a/src/im-application-list.c b/src/im-application-list.c index 33f06ab..920626d 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -39,7 +39,10 @@ G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT); enum { SOURCE_ADDED, + SOURCE_CHANGED, + SOURCE_REMOVED, MESSAGE_ADDED, + MESSAGE_REMOVED, N_SIGNALS }; @@ -121,6 +124,34 @@ im_application_list_class_init (ImApplicationListClass *klass) G_TYPE_STRING, G_TYPE_BOOLEAN); + signals[SOURCE_CHANGED] = g_signal_new ("source-changed", + IM_TYPE_APPLICATION_LIST, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 8, + G_TYPE_DESKTOP_APP_INFO, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_UINT, + G_TYPE_INT64, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + + signals[SOURCE_REMOVED] = g_signal_new ("source-removed", + IM_TYPE_APPLICATION_LIST, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 2, + G_TYPE_DESKTOP_APP_INFO, + G_TYPE_STRING); + signals[MESSAGE_ADDED] = g_signal_new ("message-added", IM_TYPE_APPLICATION_LIST, G_SIGNAL_RUN_FIRST, @@ -137,6 +168,17 @@ im_application_list_class_init (ImApplicationListClass *klass) G_TYPE_STRING, G_TYPE_INT64, G_TYPE_BOOLEAN); + + signals[MESSAGE_REMOVED] = g_signal_new ("message-removed", + IM_TYPE_APPLICATION_LIST, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, + 2, + G_TYPE_DESKTOP_APP_INFO, + G_TYPE_STRING); } static void @@ -199,6 +241,63 @@ im_application_list_remove (ImApplicationList *list, g_action_muxer_remove (list->muxer, id); } +static void +im_application_list_source_added (Application *app, + guint position, + GVariant *source) +{ + const gchar *id; + const gchar *label; + const gchar *iconstr; + guint32 count; + gint64 time; + const gchar *string; + gboolean draws_attention; + GSimpleAction *action; + + g_variant_get (source, "(&s&s&sux&sb)", + &id, &label, &iconstr, &count, &time, &string, &draws_attention); + + action = g_simple_action_new_stateful (id, NULL, g_variant_new_uint32 (count)); + g_simple_action_group_insert (app->actions, G_ACTION (action)); + + g_signal_emit (app->list, signals[SOURCE_ADDED], 0, + app->info, id, label, iconstr, count, time, string, draws_attention); + + g_object_unref (action); +} + +static void +im_application_list_source_changed (Application *app, + GVariant *source) +{ + const gchar *id; + const gchar *label; + const gchar *iconstr; + guint32 count; + gint64 time; + const gchar *string; + gboolean draws_attention; + + g_variant_get (source, "(&s&s&sux&sb)", + &id, &label, &iconstr, &count, &time, &string, &draws_attention); + + g_action_group_change_action_state (G_ACTION_GROUP (app->actions), id, + g_variant_new_uint32 (count)); + + g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, + app->info, id, label, iconstr, count, time, string, draws_attention); +} + +static void +im_application_list_source_removed (Application *app, + const gchar *id) +{ + g_simple_action_group_remove (app->actions, id); + + g_signal_emit (app->list, signals[SOURCE_REMOVED], 0, app->info, id); +} + static void im_application_list_sources_listed (GObject *source_object, GAsyncResult *result, @@ -211,28 +310,16 @@ im_application_list_sources_listed (GObject *source_object, if (indicator_messages_application_call_list_sources_finish (app->proxy, &sources, result, &error)) { GVariantIter iter; - const gchar *id; - const gchar *label; - const gchar *iconstr; - guint32 count; - gint64 time; - const gchar *string; - gboolean draws_attention; + GVariant *source; + guint i = 0; g_variant_iter_init (&iter, sources); - while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr, &count, - &time, &string, &draws_attention)) + while ((source = g_variant_iter_next_value (&iter))) { - GSimpleAction *action; - - action = g_simple_action_new_stateful (id, NULL, g_variant_new_uint32 (count)); - g_simple_action_group_insert (app->actions, G_ACTION (action)); - - g_signal_emit (app->list, signals[SOURCE_ADDED], 0, - app->info, id, label, iconstr, count, time, string, draws_attention); - - g_object_unref (action); + im_application_list_source_added (app, i++, source); + g_variant_unref (source); } + g_variant_unref (sources); } else @@ -242,6 +329,40 @@ im_application_list_sources_listed (GObject *source_object, } } +static void +im_application_list_message_added (Application *app, + GVariant *message) +{ + const gchar *id; + const gchar *iconstr; + const gchar *title; + const gchar *subtitle; + const gchar *body; + gint64 time; + gboolean draws_attention; + GSimpleAction *action; + + g_variant_get (message, "(&s&s&s&s&sxb)", + &id, &iconstr, &title, &subtitle, &body, &time, &draws_attention); + + action = g_simple_action_new (id, NULL); + g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (app->actions), G_ACTION (action)); + + g_signal_emit (app->list, signals[MESSAGE_ADDED], 0, + app->info, id, iconstr, title, subtitle, body, time, draws_attention); + + g_object_unref (action); +} + +static void +im_application_list_message_removed (Application *app, + const gchar *id) +{ + g_simple_action_group_remove (app->actions, id); + + g_signal_emit (app->list, signals[MESSAGE_REMOVED], 0, app->info, id); +} + static void im_application_list_messages_listed (GObject *source_object, GAsyncResult *result, @@ -254,27 +375,13 @@ im_application_list_messages_listed (GObject *source_object, if (indicator_messages_application_call_list_messages_finish (app->proxy, &messages, result, &error)) { GVariantIter iter; - const gchar *id; - const gchar *iconstr; - const gchar *title; - const gchar *subtitle; - const gchar *body; - gint64 time; - gboolean draws_attention; + GVariant *message; g_variant_iter_init (&iter, messages); - while (g_variant_iter_next (&iter, "(&s&s&s&s&sxb)", &id, &iconstr, &title, &subtitle, &body, - &time, &draws_attention)) + while ((message = g_variant_iter_next_value (&iter))) { - GSimpleAction *action; - - action = g_simple_action_new (id, NULL); - g_simple_action_group_insert (G_SIMPLE_ACTION_GROUP (app->actions), G_ACTION (action)); - - g_signal_emit (app->list, signals[MESSAGE_ADDED], 0, - app->info, id, iconstr, title, subtitle, body, time, draws_attention); - - g_object_unref (action); + im_application_list_message_added (app, message); + g_variant_unref (message); } g_variant_unref (messages); @@ -306,6 +413,12 @@ im_application_list_proxy_created (GObject *source_object, im_application_list_sources_listed, app); indicator_messages_application_call_list_messages (app->proxy, app->cancellable, im_application_list_messages_listed, app); + + g_signal_connect_swapped (app->proxy, "source-added", G_CALLBACK (im_application_list_source_added), app); + g_signal_connect_swapped (app->proxy, "source-changed", G_CALLBACK (im_application_list_source_changed), app); + g_signal_connect_swapped (app->proxy, "source-removed", G_CALLBACK (im_application_list_source_removed), app); + g_signal_connect_swapped (app->proxy, "message-added", G_CALLBACK (im_application_list_message_added), app); + g_signal_connect_swapped (app->proxy, "message-removed", G_CALLBACK (im_application_list_message_removed), app); } void diff --git a/src/messages-service.c b/src/messages-service.c index a65e2d8..467224d 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -267,8 +267,12 @@ main (int argc, char ** argv) applications = im_application_list_new (); g_signal_connect_swapped (applications, "source-added", G_CALLBACK (im_phone_menu_add_source), menu); + g_signal_connect_swapped (applications, "source-removed", + G_CALLBACK (im_phone_menu_remove_source), menu); g_signal_connect_swapped (applications, "message-added", G_CALLBACK (im_phone_menu_add_message), menu); + g_signal_connect_swapped (applications, "message-removed", + G_CALLBACK (im_phone_menu_remove_message), menu); g_main_loop_run(mainloop); -- cgit v1.2.3 From 15f2eef7082f9a68b1511f0868cdd60558b3a4f6 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 20 Nov 2012 23:15:32 +0100 Subject: libmessaging-menu: emit the right signal when a message is removed --- libmessaging-menu/messaging-menu-app.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmessaging-menu/messaging-menu-app.c b/libmessaging-menu/messaging-menu-app.c index bc7e978..61547c5 100644 --- a/libmessaging-menu/messaging-menu-app.c +++ b/libmessaging-menu/messaging-menu-app.c @@ -1397,5 +1397,5 @@ messaging_menu_app_remove_message_by_id (MessagingMenuApp *app, g_return_if_fail (id != NULL); if (messaging_menu_app_remove_message_internal (app, id)) - indicator_messages_application_emit_source_removed (app->app_interface, id); + indicator_messages_application_emit_message_removed (app->app_interface, id); } -- cgit v1.2.3 From d22b49e5fee5ae352ec6050e63181850a857fb3a Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 21 Nov 2012 00:02:12 +0100 Subject: Remove applications from the menu when the disappear from the bus --- src/im-application-list.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/im-phone-menu.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/im-phone-menu.h | 3 +++ src/messages-service.c | 2 ++ 4 files changed, 90 insertions(+) diff --git a/src/im-application-list.c b/src/im-application-list.c index 920626d..6da2950 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -43,6 +43,7 @@ enum SOURCE_REMOVED, MESSAGE_ADDED, MESSAGE_REMOVED, + APP_STOPPED, N_SIGNALS }; @@ -179,6 +180,16 @@ im_application_list_class_init (ImApplicationListClass *klass) 2, G_TYPE_DESKTOP_APP_INFO, G_TYPE_STRING); + + signals[APP_STOPPED] = g_signal_new ("app-stopped", + IM_TYPE_APPLICATION_LIST, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + G_TYPE_DESKTOP_APP_INFO); } static void @@ -393,6 +404,31 @@ im_application_list_messages_listed (GObject *source_object, } } +static void +im_application_list_app_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + Application *app = user_data; + + if (app->cancellable) + { + g_cancellable_cancel (app->cancellable); + g_clear_object (&app->cancellable); + } + g_clear_object (&app->proxy); + + /* clear actions by creating a new action group and overriding it in + * the muxer */ + g_object_unref (app->actions); + app->actions = g_simple_action_group_new (); + g_action_muxer_insert (app->list->muxer, + g_app_info_get_id (G_APP_INFO (app->info)), + G_ACTION_GROUP (app->actions)); + + g_signal_emit (app->list, signals[APP_STOPPED], 0, app->info); +} + static void im_application_list_proxy_created (GObject *source_object, GAsyncResult *result, @@ -419,6 +455,12 @@ im_application_list_proxy_created (GObject *source_object, g_signal_connect_swapped (app->proxy, "source-removed", G_CALLBACK (im_application_list_source_removed), app); g_signal_connect_swapped (app->proxy, "message-added", G_CALLBACK (im_application_list_message_added), app); g_signal_connect_swapped (app->proxy, "message-removed", G_CALLBACK (im_application_list_message_removed), app); + + g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (G_DBUS_PROXY (app->proxy)), + g_dbus_proxy_get_name (G_DBUS_PROXY (app->proxy)), + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, im_application_list_app_vanished, + app, NULL); } void diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c index abb3a11..43b7a6c 100644 --- a/src/im-phone-menu.c +++ b/src/im-phone-menu.c @@ -214,3 +214,46 @@ im_phone_menu_remove_source (ImPhoneMenu *menu, g_free (action_name); } + +static void +im_phone_menu_remove_all_for_app (GMenu *menu, + GDesktopAppInfo *app) +{ + gchar *prefix; + gint n_items; + gint i = 0; + + prefix = g_strconcat (g_app_info_get_id (G_APP_INFO (app)), ".", NULL); + + n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu)); + while (i < n_items) + { + gchar *action; + + g_menu_model_get_item_attribute (G_MENU_MODEL (menu), i, G_MENU_ATTRIBUTE_ACTION, "s", &action); + if (g_str_has_prefix (action, prefix)) + { + g_menu_remove (menu, i); + n_items--; + } + else + { + i++; + } + + g_free (action); + } + + g_free (prefix); +} + +void +im_phone_menu_remove_application (ImPhoneMenu *menu, + GDesktopAppInfo *app) +{ + g_return_if_fail (IM_IS_PHONE_MENU (menu)); + g_return_if_fail (G_IS_DESKTOP_APP_INFO (app)); + + im_phone_menu_remove_all_for_app (menu->source_section, app); + im_phone_menu_remove_all_for_app (menu->message_section, app); +} diff --git a/src/im-phone-menu.h b/src/im-phone-menu.h index f7cc645..91aae2c 100644 --- a/src/im-phone-menu.h +++ b/src/im-phone-menu.h @@ -64,4 +64,7 @@ void im_phone_menu_remove_source (ImPhoneMenu *men GDesktopAppInfo *app, const gchar *id); +void im_phone_menu_remove_application (ImPhoneMenu *menu, + GDesktopAppInfo *app); + #endif diff --git a/src/messages-service.c b/src/messages-service.c index 467224d..18f3d0a 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -273,6 +273,8 @@ main (int argc, char ** argv) G_CALLBACK (im_phone_menu_add_message), menu); g_signal_connect_swapped (applications, "message-removed", G_CALLBACK (im_phone_menu_remove_message), menu); + g_signal_connect_swapped (applications, "app-stopped", + G_CALLBACK (im_phone_menu_remove_application), menu); g_main_loop_run(mainloop); -- cgit v1.2.3 From 1d96aab069071bd6f73b3be8beb40ca25d37fa86 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 21 Nov 2012 00:16:44 +0100 Subject: Replace app when another process is registering with the same id --- src/im-application-list.c | 28 +++++++++++++--------------- src/im-application-list.h | 2 +- src/messages-service.c | 7 +------ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/im-application-list.c b/src/im-application-list.c index 6da2950..3221413 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -205,7 +205,7 @@ im_application_list_new (void) return g_object_new (IM_TYPE_APPLICATION_LIST, NULL); } -gboolean +void im_application_list_add (ImApplicationList *list, const gchar *desktop_id) { @@ -213,20 +213,18 @@ im_application_list_add (ImApplicationList *list, Application *app; const gchar *id; - g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), FALSE); - g_return_val_if_fail (desktop_id != NULL, FALSE); + g_return_if_fail (IM_IS_APPLICATION_LIST (list)); + g_return_if_fail (desktop_id != NULL); - if (g_hash_table_contains (list->applications, desktop_id)) - { - g_warning ("an application with id '%s' already exists", desktop_id); - return FALSE; - } + app = g_hash_table_lookup (list->applications, desktop_id); + if (app) + return; info = g_desktop_app_info_new (desktop_id); if (!info) { - g_warning ("application with id '%s' already exists", desktop_id); - return FALSE; + g_warning ("an application with id '%s' is no installed", desktop_id); + return; } id = g_app_info_get_id (G_APP_INFO (info)); @@ -238,8 +236,6 @@ im_application_list_add (ImApplicationList *list, g_hash_table_insert (list->applications, (gpointer) id, app); g_action_muxer_insert (list->muxer, id, G_ACTION_GROUP (app->actions)); - - return TRUE; } void @@ -483,9 +479,11 @@ im_application_list_set_remote (ImApplicationList *list, if (app->proxy || app->cancellable) { - g_warning ("application '%s' is already running on '%s'", - id, g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy))); - return; + g_warning ("replacing '%s' at %s with %s", id, unique_bus_name, + g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy))); + g_cancellable_cancel (app->cancellable); + g_object_unref (app->cancellable); + g_clear_object (&app->proxy); } app->cancellable = g_cancellable_new (); diff --git a/src/im-application-list.h b/src/im-application-list.h index 3bf21c9..ecba312 100644 --- a/src/im-application-list.h +++ b/src/im-application-list.h @@ -35,7 +35,7 @@ GType im_application_list_get_type (void); ImApplicationList * im_application_list_new (void); -gboolean im_application_list_add (ImApplicationList *list, +void im_application_list_add (ImApplicationList *list, const gchar *desktop_id); void im_application_list_remove (ImApplicationList *list, diff --git a/src/messages-service.c b/src/messages-service.c index 18f3d0a..b3731a8 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -119,12 +119,7 @@ register_application (IndicatorMessagesService *service, GDBusConnection *bus; const gchar *sender; - if (!im_application_list_add (applications, desktop_id)) { - g_dbus_method_invocation_return_dbus_error (invocation, - "com.canonical.indicator.messages.RegistrationFailed", - "registration failed"); - return; - } + im_application_list_add (applications, desktop_id); bus = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (service)); sender = g_dbus_method_invocation_get_sender (invocation); -- cgit v1.2.3 From 0a9533c90d46c4bfda4e0527f5475ce8c22c08e7 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 21 Nov 2012 00:28:12 +0100 Subject: Remove application messages when it unregisters itself --- src/im-application-list.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/im-application-list.c b/src/im-application-list.c index 3221413..9e9df9d 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -242,10 +242,19 @@ void im_application_list_remove (ImApplicationList *list, const gchar *id) { + Application *app; + g_return_if_fail (IM_IS_APPLICATION_LIST (list)); - g_hash_table_remove (list->applications, id); - g_action_muxer_remove (list->muxer, id); + app = g_hash_table_lookup (list->applications, id); + if (app) + { + if (app->proxy || app->cancellable) + g_signal_emit (app->list, signals[APP_STOPPED], 0, app->info); + + g_hash_table_remove (list->applications, id); + g_action_muxer_remove (list->muxer, id); + } } static void @@ -401,11 +410,11 @@ im_application_list_messages_listed (GObject *source_object, } static void -im_application_list_app_vanished (GDBusConnection *connection, - const gchar *name, - gpointer user_data) +im_application_list_unset_remote (Application *app) { - Application *app = user_data; + gboolean was_running; + + was_running = app->proxy || app->cancellable; if (app->cancellable) { @@ -422,7 +431,18 @@ im_application_list_app_vanished (GDBusConnection *connection, g_app_info_get_id (G_APP_INFO (app->info)), G_ACTION_GROUP (app->actions)); - g_signal_emit (app->list, signals[APP_STOPPED], 0, app->info); + if (was_running) + g_signal_emit (app->list, signals[APP_STOPPED], 0, app->info); +} + +static void +im_application_list_app_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + Application *app = user_data; + + im_application_list_unset_remote (app); } static void @@ -481,9 +501,7 @@ im_application_list_set_remote (ImApplicationList *list, { g_warning ("replacing '%s' at %s with %s", id, unique_bus_name, g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy))); - g_cancellable_cancel (app->cancellable); - g_object_unref (app->cancellable); - g_clear_object (&app->proxy); + im_application_list_unset_remote (app); } app->cancellable = g_cancellable_new (); -- cgit v1.2.3 From 7d78b08907c94be166da15adc9b7dad3c282d0f2 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 21 Nov 2012 11:25:20 +0100 Subject: ImApplicationList: no need to include the dynamic data in the signals This data can (and should) always be retrieved via actions. --- src/im-application-list.c | 22 ++++++---------------- src/im-phone-menu.c | 5 +---- src/im-phone-menu.h | 5 +---- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/im-application-list.c b/src/im-application-list.c index 9e9df9d..05d3a52 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -115,15 +115,11 @@ im_application_list_class_init (ImApplicationListClass *klass) NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, - 8, + 4, G_TYPE_DESKTOP_APP_INFO, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_UINT, - G_TYPE_INT64, - G_TYPE_STRING, - G_TYPE_BOOLEAN); + G_TYPE_STRING); signals[SOURCE_CHANGED] = g_signal_new ("source-changed", IM_TYPE_APPLICATION_LIST, @@ -132,15 +128,11 @@ im_application_list_class_init (ImApplicationListClass *klass) NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, - 8, + 4, G_TYPE_DESKTOP_APP_INFO, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_UINT, - G_TYPE_INT64, - G_TYPE_STRING, - G_TYPE_BOOLEAN); + G_TYPE_STRING); signals[SOURCE_REMOVED] = g_signal_new ("source-removed", IM_TYPE_APPLICATION_LIST, @@ -277,8 +269,7 @@ im_application_list_source_added (Application *app, action = g_simple_action_new_stateful (id, NULL, g_variant_new_uint32 (count)); g_simple_action_group_insert (app->actions, G_ACTION (action)); - g_signal_emit (app->list, signals[SOURCE_ADDED], 0, - app->info, id, label, iconstr, count, time, string, draws_attention); + g_signal_emit (app->list, signals[SOURCE_ADDED], 0, app->info, id, label, iconstr); g_object_unref (action); } @@ -301,8 +292,7 @@ im_application_list_source_changed (Application *app, g_action_group_change_action_state (G_ACTION_GROUP (app->actions), id, g_variant_new_uint32 (count)); - g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, - app->info, id, label, iconstr, count, time, string, draws_attention); + g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, app->info, id, label, iconstr); } static void diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c index 43b7a6c..0ba41c4 100644 --- a/src/im-phone-menu.c +++ b/src/im-phone-menu.c @@ -172,10 +172,7 @@ 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) + const gchar *iconstr) { GMenuItem *item; gchar *action_name; diff --git a/src/im-phone-menu.h b/src/im-phone-menu.h index 91aae2c..b0b6b4f 100644 --- a/src/im-phone-menu.h +++ b/src/im-phone-menu.h @@ -55,10 +55,7 @@ void im_phone_menu_add_source (ImPhoneMenu *men GDesktopAppInfo *app, const gchar *id, const gchar *label, - const gchar *iconstr, - guint32 count, - gint64 time, - const gchar *string); + const gchar *iconstr); void im_phone_menu_remove_source (ImPhoneMenu *menu, GDesktopAppInfo *app, -- cgit v1.2.3 From e8eda4af8432d36d82b1124a4bad0f5eee876188 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 21 Nov 2012 13:40:11 +0100 Subject: ImApplicationList: fix typos Thanks Olivier! --- src/im-application-list.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/im-application-list.c b/src/im-application-list.c index 05d3a52..732a117 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -215,7 +215,7 @@ im_application_list_add (ImApplicationList *list, info = g_desktop_app_info_new (desktop_id); if (!info) { - g_warning ("an application with id '%s' is no installed", desktop_id); + g_warning ("an application with id '%s' is not installed", desktop_id); return; } @@ -483,7 +483,7 @@ im_application_list_set_remote (ImApplicationList *list, app = g_hash_table_lookup (list->applications, id); if (!app) { - g_warning ("'%s' is not a registered appliction", id); + g_warning ("'%s' is not a registered application", id); return; } -- cgit v1.2.3