aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Uebernickel <lars.uebernickel@canonical.com>2012-11-20 22:20:23 +0100
committerLars Uebernickel <lars.uebernickel@canonical.com>2012-11-20 22:20:23 +0100
commit2021da310c84d28efcf9bb359b7a8f7065743267 (patch)
treea3b1f70e0eaad9fc75218c7269a1267bcc6f1704
parent6f990698f610eb444845f36a70cad04bca2415f3 (diff)
downloadayatana-indicator-messages-2021da310c84d28efcf9bb359b7a8f7065743267.tar.gz
ayatana-indicator-messages-2021da310c84d28efcf9bb359b7a8f7065743267.tar.bz2
ayatana-indicator-messages-2021da310c84d28efcf9bb359b7a8f7065743267.zip
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.
-rw-r--r--src/Makefile.am4
-rw-r--r--src/im-application-list.c348
-rw-r--r--src/im-application-list.h52
-rw-r--r--src/messages-service.c176
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;
}