aboutsummaryrefslogtreecommitdiff
path: root/src/im-application-list.c
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 /src/im-application-list.c
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.
Diffstat (limited to 'src/im-application-list.c')
-rw-r--r--src/im-application-list.c348
1 files changed, 348 insertions, 0 deletions
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);
+}