aboutsummaryrefslogtreecommitdiff
path: root/src/im-application-list.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/im-application-list.c')
-rw-r--r--src/im-application-list.c1139
1 files changed, 0 insertions, 1139 deletions
diff --git a/src/im-application-list.c b/src/im-application-list.c
deleted file mode 100644
index bba7972..0000000
--- a/src/im-application-list.c
+++ /dev/null
@@ -1,1139 +0,0 @@
-/*
- * 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>
-#include <string.h>
-
-typedef GObjectClass ImApplicationListClass;
-
-struct _ImApplicationList
-{
- GObject parent;
-
- GHashTable *applications;
- GActionMuxer *muxer;
-
- GSimpleActionGroup * globalactions;
- GSimpleAction * statusaction;
-
- GHashTable *app_status;
-};
-
-G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT);
-G_DEFINE_QUARK (draws_attention, message_action_draws_attention);
-
-enum
-{
- SOURCE_ADDED,
- SOURCE_CHANGED,
- SOURCE_REMOVED,
- MESSAGE_ADDED,
- MESSAGE_REMOVED,
- APP_ADDED,
- APP_STOPPED,
- REMOVE_ALL,
- STATUS_SET,
- N_SIGNALS
-};
-
-static guint signals[N_SIGNALS];
-
-typedef struct
-{
- ImApplicationList *list;
- GDesktopAppInfo *info;
- gchar *id;
- IndicatorMessagesApplication *proxy;
- GActionMuxer *muxer;
- GSimpleActionGroup *actions;
- GSimpleActionGroup *source_actions;
- GSimpleActionGroup *message_actions;
- GActionMuxer *message_sub_actions;
- GCancellable *cancellable;
- gboolean draws_attention;
-} Application;
-
-
-/* Prototypes */
-static void status_activated (GSimpleAction * action,
- GVariant * param,
- gpointer user_data);
-
-static void
-application_free (gpointer data)
-{
- Application *app = data;
-
- if (!app)
- return;
-
- g_object_unref (app->info);
- g_free (app->id);
-
- if (app->cancellable)
- {
- g_cancellable_cancel (app->cancellable);
- g_clear_object (&app->cancellable);
- }
-
- if (app->proxy)
- g_object_unref (app->proxy);
-
- if (app->muxer)
- {
- g_object_unref (app->muxer);
- g_object_unref (app->source_actions);
- g_object_unref (app->message_actions);
- g_object_unref (app->message_sub_actions);
- }
-
- g_slice_free (Application, app);
-}
-
-static gboolean
-application_draws_attention (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- Application *app = value;
-
- return app->draws_attention;
-}
-
-static void
-im_application_list_update_draws_attention (ImApplicationList *list)
-{
- const gchar *icon_name;
- GVariant *state;
- GActionGroup *main_actions;
-
- if (g_hash_table_find (list->applications, application_draws_attention, NULL))
- icon_name = "indicator-messages-new";
- else
- icon_name = "indicator-messages";
-
- main_actions = g_action_muxer_get_group (list->muxer, NULL);
- state = g_variant_new ("(sssb)", "", icon_name, "Messages", TRUE);
- g_action_group_change_action_state (main_actions, "messages", state);
-}
-
-/* Check a source action to see if it draws */
-static gboolean
-app_source_action_check_draw (Application * app, const gchar * action_name)
-{
- gboolean retval = FALSE;
- GVariant * state;
- GVariant * draw;
-
- state = g_action_group_get_action_state (G_ACTION_GROUP(app->source_actions), action_name);
-
- /* uxsb */
- draw = g_variant_get_child_value(state, 3);
- retval = g_variant_get_boolean(draw);
-
- g_variant_unref(draw);
- g_variant_unref(state);
-
- return retval;
-}
-
-/* Check a message action to see if it draws */
-static gboolean
-app_message_action_check_draw (Application * app, const gchar * action_name)
-{
- GAction * action = NULL;
- action = g_simple_action_group_lookup (app->message_actions, action_name);
- return GPOINTER_TO_INT(g_object_get_qdata(G_OBJECT(action), message_action_draws_attention_quark()));
-}
-
-/* Regenerate the draw attention flag based on the sources and messages
- that we have in the action groups */
-static void
-app_check_draw_attention (Application * app)
-{
- gchar **source_actions = NULL;
- gchar **message_actions = NULL;
- gchar **it;
-
- source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
- for (it = source_actions; *it && !app->draws_attention; it++)
- app->draws_attention = app_source_action_check_draw (app, *it);
-
- message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
- for (it = message_actions; *it; it++)
- app->draws_attention = app_message_action_check_draw (app, *it);
-
- g_strfreev (source_actions);
- g_strfreev (message_actions);
-
- return;
-}
-
-/* Remove a source from an application, signal up and update the status
- of the draws attention flag. */
-static void
-im_application_list_source_removed (Application *app,
- const gchar *id)
-{
- g_simple_action_group_remove (app->source_actions, id);
-
- g_signal_emit (app->list, signals[SOURCE_REMOVED], 0, app->id, id);
-
- if (app->draws_attention)
- {
- app->draws_attention = FALSE;
- app_check_draw_attention(app);
- }
-
- im_application_list_update_draws_attention (app->list);
-}
-
-static void
-im_application_list_source_activated (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- Application *app = user_data;
- const gchar *source_id;
-
- source_id = g_action_get_name (G_ACTION (action));
-
- if (g_variant_get_boolean (parameter))
- {
- indicator_messages_application_call_activate_source (app->proxy,
- source_id,
- app->cancellable,
- NULL, NULL);
- }
- else
- {
- const gchar *sources[] = { source_id, NULL };
- const gchar *messages[] = { NULL };
- indicator_messages_application_call_dismiss (app->proxy, sources, messages,
- app->cancellable, NULL, NULL);
- }
-
- im_application_list_source_removed (app, source_id);
-}
-
-static void
-im_application_list_message_removed (Application *app,
- const gchar *id)
-{
- g_simple_action_group_remove (app->message_actions, id);
- g_action_muxer_remove (app->message_sub_actions, id);
-
- im_application_list_update_draws_attention (app->list);
-
- g_signal_emit (app->list, signals[MESSAGE_REMOVED], 0, app->id, id);
-}
-
-static void
-im_application_list_message_activated (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- Application *app = user_data;
- const gchar *message_id;
-
- message_id = g_action_get_name (G_ACTION (action));
-
- if (g_variant_get_boolean (parameter))
- {
- indicator_messages_application_call_activate_message (app->proxy,
- message_id,
- "",
- g_variant_new_array (G_VARIANT_TYPE_VARIANT, NULL, 0),
- app->cancellable,
- NULL, NULL);
- }
- else
- {
- const gchar *sources[] = { NULL };
- const gchar *messages[] = { message_id, NULL };
- indicator_messages_application_call_dismiss (app->proxy, sources, messages,
- app->cancellable, NULL, NULL);
- }
-
- im_application_list_message_removed (app, message_id);
-}
-
-static void
-im_application_list_sub_message_activated (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- Application *app = user_data;
- const gchar *message_id;
- const gchar *action_id;
- GVariantBuilder builder;
-
- message_id = g_object_get_data (G_OBJECT (action), "message");
- action_id = g_action_get_name (G_ACTION (action));
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
- if (parameter)
- g_variant_builder_add (&builder, "v", parameter);
-
- indicator_messages_application_call_activate_message (app->proxy,
- message_id,
- action_id,
- g_variant_builder_end (&builder),
- app->cancellable,
- NULL, NULL);
-
- im_application_list_message_removed (app, message_id);
-}
-
-static void
-im_application_list_remove_all (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- ImApplicationList *list = user_data;
- GHashTableIter iter;
- Application *app;
-
- g_signal_emit (list, signals[REMOVE_ALL], 0);
-
- g_hash_table_iter_init (&iter, list->applications);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &app))
- {
- gchar **source_actions;
- gchar **message_actions;
- gchar **it;
-
- app->draws_attention = FALSE;
-
- source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
- for (it = source_actions; *it; it++)
- im_application_list_source_removed (app, *it);
-
- message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
- for (it = message_actions; *it; it++)
- im_application_list_message_removed (app, *it);
-
- if (app->proxy != NULL) /* If it is remote, we tell the app we've cleared */
- {
- indicator_messages_application_call_dismiss (app->proxy,
- (const gchar * const *) source_actions,
- (const gchar * const *) message_actions,
- app->cancellable, NULL, NULL);
- }
-
- g_strfreev (source_actions);
- g_strfreev (message_actions);
- }
-
- im_application_list_update_draws_attention (list);
-}
-
-static void
-im_application_list_dispose (GObject *object)
-{
- ImApplicationList *list = IM_APPLICATION_LIST (object);
-
- g_clear_object (&list->statusaction);
- g_clear_object (&list->globalactions);
- g_clear_pointer (&list->app_status, g_hash_table_unref);
-
- 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,
- 4,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING);
-
- 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,
- 4,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING);
-
- 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_STRING,
- G_TYPE_STRING);
-
- 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,
- 10,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_VARIANT,
- 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_STRING,
- G_TYPE_STRING);
-
- signals[APP_ADDED] = g_signal_new ("app-added",
- IM_TYPE_APPLICATION_LIST,
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE,
- 2,
- G_TYPE_STRING,
- G_TYPE_DESKTOP_APP_INFO);
-
- 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_STRING);
-
- signals[REMOVE_ALL] = g_signal_new ("remove-all",
- IM_TYPE_APPLICATION_LIST,
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- signals[STATUS_SET] = g_signal_new ("status-set",
- IM_TYPE_APPLICATION_LIST,
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_generic,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-}
-
-static void
-im_application_list_init (ImApplicationList *list)
-{
- const GActionEntry action_entries[] = {
- { "messages", NULL, NULL, "('', 'indicator-messages', 'Messages', true)", NULL },
- { "remove-all", im_application_list_remove_all }
- };
-
- list->applications = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, application_free);
- list->app_status = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- list->globalactions = g_simple_action_group_new ();
- g_simple_action_group_add_entries (list->globalactions, action_entries, G_N_ELEMENTS (action_entries), list);
-
- list->statusaction = g_simple_action_new_stateful("status", G_VARIANT_TYPE_STRING, g_variant_new_string("offline"));
- g_signal_connect(list->statusaction, "activate", G_CALLBACK(status_activated), list);
- g_simple_action_group_insert(list->globalactions, G_ACTION(list->statusaction));
-
- list->muxer = g_action_muxer_new ();
- g_action_muxer_insert (list->muxer, NULL, G_ACTION_GROUP (list->globalactions));
-
-}
-
-ImApplicationList *
-im_application_list_new (void)
-{
- return g_object_new (IM_TYPE_APPLICATION_LIST, NULL);
-}
-
-static gchar *
-im_application_list_canonical_id (const gchar *id)
-{
- gchar *str;
- gchar *p;
- int len;
-
- len = strlen (id);
- if (g_str_has_suffix (id, ".desktop"))
- len -= 8;
-
- str = g_strndup (id, len);
-
- for (p = str; *p; p++)
- {
- if (*p == '.')
- *p = '_';
- }
-
- return str;
-}
-
-static Application *
-im_application_list_lookup (ImApplicationList *list,
- const gchar *desktop_id)
-{
- gchar *id;
- Application *app;
-
- id = im_application_list_canonical_id (desktop_id);
- app = g_hash_table_lookup (list->applications, id);
-
- g_free (id);
- return app;
-}
-
-void
-im_application_list_activate_launch (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- Application *app = user_data;
- GError *error = NULL;
-
- if (!g_app_info_launch (G_APP_INFO (app->info), NULL, NULL, &error))
- {
- g_warning ("unable to launch application: %s", error->message);
- g_error_free (error);
- }
-}
-
-void
-im_application_list_activate_app_action (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- Application *app = user_data;
-
- g_desktop_app_info_launch_action (app->info, g_action_get_name (G_ACTION (action)), NULL);
-}
-
-void
-im_application_list_add (ImApplicationList *list,
- const gchar *desktop_id)
-{
- GDesktopAppInfo *info;
- Application *app;
- const gchar *id;
- GSimpleActionGroup *actions;
- GSimpleAction *launch_action;
-
- g_return_if_fail (IM_IS_APPLICATION_LIST (list));
- g_return_if_fail (desktop_id != NULL);
-
- if (im_application_list_lookup (list, desktop_id))
- return;
-
- info = g_desktop_app_info_new (desktop_id);
- if (!info)
- {
- g_warning ("an application with id '%s' is not installed", desktop_id);
- return;
- }
-
- id = g_app_info_get_id (G_APP_INFO (info));
- g_return_if_fail (id != NULL);
-
- app = g_slice_new0 (Application);
- app->info = info;
- app->id = im_application_list_canonical_id (id);
- app->list = list;
- app->muxer = g_action_muxer_new ();
- app->source_actions = g_simple_action_group_new ();
- app->message_actions = g_simple_action_group_new ();
- app->message_sub_actions = g_action_muxer_new ();
- app->draws_attention = FALSE;
-
- actions = g_simple_action_group_new ();
-
- launch_action = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (FALSE));
- g_signal_connect (launch_action, "activate", G_CALLBACK (im_application_list_activate_launch), app);
- g_action_map_add_action (G_ACTION_MAP (actions), G_ACTION (launch_action));
-
- {
- const gchar *const *app_actions;
-
- for (app_actions = g_desktop_app_info_list_actions (app->info); *app_actions; app_actions++)
- {
- GSimpleAction *action;
-
- action = g_simple_action_new (*app_actions, NULL);
- g_signal_connect (action, "activate", G_CALLBACK (im_application_list_activate_app_action), app);
- g_action_map_add_action (G_ACTION_MAP (actions), G_ACTION (action));
-
- g_object_unref (action);
- }
- }
-
- g_action_muxer_insert (app->muxer, NULL, G_ACTION_GROUP (actions));
- g_action_muxer_insert (app->muxer, "src", G_ACTION_GROUP (app->source_actions));
- g_action_muxer_insert (app->muxer, "msg", G_ACTION_GROUP (app->message_actions));
- g_action_muxer_insert (app->muxer, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
-
- g_hash_table_insert (list->applications, (gpointer) app->id, app);
- g_action_muxer_insert (list->muxer, app->id, G_ACTION_GROUP (app->muxer));
-
- g_signal_emit (app->list, signals[APP_ADDED], 0, app->id, app->info);
-
- g_object_unref (launch_action);
- g_object_unref (actions);
-}
-
-void
-im_application_list_remove (ImApplicationList *list,
- const gchar *id)
-{
- Application *app;
-
- g_return_if_fail (IM_IS_APPLICATION_LIST (list));
-
- app = im_application_list_lookup (list, id);
- if (app)
- {
- if (app->proxy || app->cancellable)
- g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
-
- g_hash_table_remove (list->applications, id);
- g_action_muxer_remove (list->muxer, id);
-
- im_application_list_update_draws_attention (list);
- }
-}
-
-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;
- GVariant *state;
- GSimpleAction *action;
-
- g_variant_get (source, "(&s&s&sux&sb)",
- &id, &label, &iconstr, &count, &time, &string, &draws_attention);
-
- state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
- action = g_simple_action_new_stateful (id, G_VARIANT_TYPE_BOOLEAN, state);
- g_signal_connect (action, "activate", G_CALLBACK (im_application_list_source_activated), app);
-
- g_simple_action_group_insert (app->source_actions, G_ACTION (action));
-
- g_signal_emit (app->list, signals[SOURCE_ADDED], 0, app->id, id, label, iconstr);
-
- if (draws_attention)
- app->draws_attention = TRUE;
-
- im_application_list_update_draws_attention (app->list);
-
- 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->source_actions), id,
- g_variant_new ("(uxsb)", count, time, string, draws_attention));
-
- g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, app->id, id, label, iconstr);
-
- im_application_list_update_draws_attention (app->list);
-}
-
-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;
- GVariant *source;
- guint i = 0;
-
- g_variant_iter_init (&iter, sources);
- while ((source = g_variant_iter_next_value (&iter)))
- {
- im_application_list_source_added (app, i++, source);
- g_variant_unref (source);
- }
-
- g_variant_unref (sources);
- }
- else
- {
- g_warning ("could not fetch the list of sources: %s", error->message);
- g_error_free (error);
- }
-}
-
-static gchar *
-get_symbolic_app_icon_string (GIcon *icon)
-{
- const gchar * const *names;
- gchar *symbolic_name;
- GIcon *symbolic_icon;
- gchar *str;
-
- if (!G_IS_THEMED_ICON (icon))
- return NULL;
-
- names = g_themed_icon_get_names (G_THEMED_ICON (icon));
- if (!names || !names[0])
- return NULL;
-
- symbolic_icon = g_themed_icon_new_from_names ((gchar **) names, -1);
-
- symbolic_name = g_strconcat (names[0], "-symbolic", NULL);
- g_themed_icon_prepend_name (G_THEMED_ICON (symbolic_icon), symbolic_name);
-
- str = g_icon_to_string (symbolic_icon);
-
- g_free (symbolic_name);
- g_object_unref (symbolic_icon);
- return str;
-}
-
-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;
- GVariantIter *action_iter;
- gboolean draws_attention;
- GSimpleAction *action;
- GIcon *app_icon;
- gchar *app_iconstr = NULL;
- GVariant *actions = NULL;
-
- g_variant_get (message, "(&s&s&s&s&sxaa{sv}b)",
- &id, &iconstr, &title, &subtitle, &body, &time, &action_iter, &draws_attention);
-
- app_icon = g_app_info_get_icon (G_APP_INFO (app->info));
- if (app_icon)
- app_iconstr = get_symbolic_app_icon_string (app_icon);
-
- action = g_simple_action_new (id, G_VARIANT_TYPE_BOOLEAN);
- g_object_set_qdata(G_OBJECT(action), message_action_draws_attention_quark(), GINT_TO_POINTER(draws_attention));
- g_signal_connect (action, "activate", G_CALLBACK (im_application_list_message_activated), app);
- g_simple_action_group_insert (app->message_actions, G_ACTION (action));
-
- {
- GVariant *entry;
- GSimpleActionGroup *action_group;
- GVariantBuilder actions_builder;
-
- g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
- action_group = g_simple_action_group_new ();
-
- while ((entry = g_variant_iter_next_value (action_iter)))
- {
- const gchar *name;
- GSimpleAction *action;
- GVariant *label;
- const gchar *type = NULL;
- GVariant *hint;
- GVariantBuilder dict_builder;
- gchar *prefixed_name;
-
- if (!g_variant_lookup (entry, "name", "&s", &name))
- {
- g_warning ("action dictionary for message '%s' is missing 'name' key", id);
- continue;
- }
-
- label = g_variant_lookup_value (entry, "label", G_VARIANT_TYPE_STRING);
- g_variant_lookup (entry, "parameter-type", "&g", &type);
- hint = g_variant_lookup_value (entry, "parameter-hint", NULL);
-
- action = g_simple_action_new (name, type ? G_VARIANT_TYPE (type) : NULL);
- g_object_set_data_full (G_OBJECT (action), "message", g_strdup (id), g_free);
- g_signal_connect (action, "activate", G_CALLBACK (im_application_list_sub_message_activated), app);
- g_simple_action_group_insert (action_group, G_ACTION (action));
-
- g_variant_builder_init (&dict_builder, G_VARIANT_TYPE ("a{sv}"));
-
- prefixed_name = g_strjoin (".", app->id, "msg-actions", id, name, NULL);
- g_variant_builder_add (&dict_builder, "{sv}", "name", g_variant_new_string (prefixed_name));
-
- if (label)
- {
- g_variant_builder_add (&dict_builder, "{sv}", "label", label);
- g_variant_unref (label);
- }
-
- if (type)
- g_variant_builder_add (&dict_builder, "{sv}", "parameter-type", g_variant_new_string (type));
-
- if (hint)
- {
- g_variant_builder_add (&dict_builder, "{sv}", "parameter-hint", hint);
- g_variant_unref (hint);
- }
-
- g_variant_builder_add (&actions_builder, "a{sv}", &dict_builder);
-
- g_object_unref (action);
- g_variant_unref (entry);
- g_free (prefixed_name);
- }
-
- g_action_muxer_insert (app->message_sub_actions, id, G_ACTION_GROUP (action_group));
- actions = g_variant_builder_end (&actions_builder);
-
- g_object_unref (action_group);
- }
-
- if (draws_attention)
- app->draws_attention = TRUE;
-
- im_application_list_update_draws_attention (app->list);
-
- g_signal_emit (app->list, signals[MESSAGE_ADDED], 0,
- app->id, app_iconstr, id, iconstr, title,
- subtitle, body, actions, time, draws_attention);
-
- g_variant_iter_free (action_iter);
- g_free (app_iconstr);
- g_object_unref (action);
-}
-
-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;
- GVariant *message;
-
- g_variant_iter_init (&iter, messages);
- while ((message = g_variant_iter_next_value (&iter)))
- {
- im_application_list_message_added (app, message);
- g_variant_unref (message);
- }
-
- 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_unset_remote (Application *app)
-{
- gboolean was_running;
-
- was_running = app->proxy || app->cancellable;
-
- 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->source_actions);
- g_object_unref (app->message_actions);
- g_object_unref (app->message_sub_actions);
- app->source_actions = g_simple_action_group_new ();
- app->message_actions = g_simple_action_group_new ();
- app->message_sub_actions = g_action_muxer_new ();
- g_action_muxer_insert (app->muxer, "src", G_ACTION_GROUP (app->source_actions));
- g_action_muxer_insert (app->muxer, "msg", G_ACTION_GROUP (app->message_actions));
- g_action_muxer_insert (app->muxer, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
-
- im_application_list_update_draws_attention (app->list);
- g_action_group_change_action_state (G_ACTION_GROUP (app->muxer), "launch", g_variant_new_boolean (FALSE));
-
- if (was_running)
- g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
-}
-
-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
-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->proxy)
- {
- if (error->code != G_IO_ERROR_CANCELLED)
- 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);
-
- 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);
-
- g_action_group_change_action_state (G_ACTION_GROUP (app->muxer), "launch", g_variant_new_boolean (TRUE));
-
- 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
-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 = im_application_list_lookup (list, id);
- if (!app)
- {
- g_warning ("'%s' is not a registered application", id);
- return;
- }
-
- if (app->cancellable)
- {
- gchar *name_owner = NULL;
-
- if (app->proxy)
- name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy));
- g_warning ("replacing '%s' at %s with %s", id, name_owner, unique_bus_name);
-
- im_application_list_unset_remote (app);
-
- g_free (name_owner);
- }
-
- 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);
-}
-
-GList *
-im_application_list_get_applications (ImApplicationList *list)
-{
- g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
-
- return g_hash_table_get_keys (list->applications);
-}
-
-GDesktopAppInfo *
-im_application_list_get_application (ImApplicationList *list,
- const gchar *id)
-{
- Application *app;
-
- g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
-
- app = g_hash_table_lookup (list->applications, id);
- return app ? app->info : NULL;
-}
-
-static void
-status_activated (GSimpleAction * action, GVariant * param, gpointer user_data)
-{
- g_return_if_fail (IM_IS_APPLICATION_LIST(user_data));
- ImApplicationList * list = IM_APPLICATION_LIST(user_data);
- const gchar * status = g_variant_get_string(param, NULL);
-
- g_simple_action_set_state(action, param);
-
- GList * appshash = g_hash_table_get_keys(list->app_status);
- GList * appsfree = g_list_copy_deep(appshash, (GCopyFunc)g_strdup, NULL);
- GList * app;
-
- for (app = appsfree; app != NULL; app = g_list_next(app)) {
- g_hash_table_insert(list->app_status, app->data, g_strdup(status));
- }
-
- g_list_free(appshash);
- g_list_free(appsfree);
-
- g_signal_emit (list, signals[STATUS_SET], 0, status);
-
- return;
-}
-
-#define STATUS_ID_OFFLINE (G_N_ELEMENTS(status_ids) - 1)
-static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };
-
-static guint
-status2val (const gchar * string)
-{
- if (string == NULL) return STATUS_ID_OFFLINE;
-
- guint i;
- for (i = 0; i < G_N_ELEMENTS(status_ids); i++) {
- if (g_strcmp0(status_ids[i], string) == 0) {
- break;
- }
- }
-
- if (i > STATUS_ID_OFFLINE)
- i = STATUS_ID_OFFLINE;
-
- return i;
-}
-
-void
-im_application_list_set_status (ImApplicationList * list, const gchar * id, const gchar *status)
-{
- g_return_if_fail (IM_IS_APPLICATION_LIST (list));
-
- g_hash_table_insert(list->app_status, im_application_list_canonical_id(id), g_strdup(status));
-
- guint final_status = STATUS_ID_OFFLINE;
-
- GList * statuses = g_hash_table_get_values(list->app_status);
- GList * statusentry;
-
- for (statusentry = statuses; statusentry != NULL; statusentry = g_list_next(statusentry)) {
- guint statusval = status2val((gchar *)statusentry->data);
- final_status = MIN(final_status, statusval);
- }
-
- g_list_free(statuses);
-
- g_simple_action_set_state(list->statusaction, g_variant_new_string(status_ids[final_status]));
-
- return;
-}
-