diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/im-application-list.c | 348 | ||||
-rw-r--r-- | src/im-application-list.h | 52 | ||||
-rw-r--r-- | src/messages-service.c | 176 |
4 files changed, 419 insertions, 161 deletions
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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Lars Uebernickel <lars.uebernickel@canonical.com> + */ + +#include "im-application-list.h" + +#include "indicator-messages-application.h" +#include "gactionmuxer.h" + +#include <gio/gdesktopappinfo.h> + +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 <http://www.gnu.org/licenses/>. + * + * Authors: + * Lars Uebernickel <lars.uebernickel@canonical.com> + */ + +#ifndef __IM_APPLICATION_LIST_H__ +#define __IM_APPLICATION_LIST_H__ + +#include <gio/gio.h> + +#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 <http://www.gnu.org/licenses/>. #include <locale.h> #include <libindicator/indicator-service.h> #include <gio/gio.h> -#include <gio/gdesktopappinfo.h> #include <glib/gi18n.h> #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; @@ -112,124 +110,6 @@ status_action_activate (GSimpleAction *action, } 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, const gchar *desktop_id, @@ -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; } |