2
* Copyright 2012 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Lars Uebernickel <lars.uebernickel@canonical.com>
20
#include "im-application-list.h"
22
#include "indicator-messages-application.h"
23
#include "gactionmuxer.h"
25
#include <gio/gdesktopappinfo.h>
28
typedef GObjectClass ImApplicationListClass;
30
struct _ImApplicationList
34
GHashTable *applications;
37
GSimpleActionGroup * globalactions;
38
GSimpleAction * statusaction;
40
GHashTable *app_status;
43
G_DEFINE_TYPE (ImApplicationList, im_application_list, G_TYPE_OBJECT);
44
G_DEFINE_QUARK (draws_attention, message_action_draws_attention);
60
static guint signals[N_SIGNALS];
64
ImApplicationList *list;
65
GDesktopAppInfo *info;
67
IndicatorMessagesApplication *proxy;
69
GSimpleActionGroup *actions;
70
GSimpleActionGroup *source_actions;
71
GSimpleActionGroup *message_actions;
72
GActionMuxer *message_sub_actions;
73
GCancellable *cancellable;
74
gboolean draws_attention;
79
static void status_activated (GSimpleAction * action,
84
application_free (gpointer data)
86
Application *app = data;
91
g_object_unref (app->info);
96
g_cancellable_cancel (app->cancellable);
97
g_clear_object (&app->cancellable);
101
g_object_unref (app->proxy);
105
g_object_unref (app->muxer);
106
g_object_unref (app->source_actions);
107
g_object_unref (app->message_actions);
108
g_object_unref (app->message_sub_actions);
111
g_slice_free (Application, app);
115
application_draws_attention (gpointer key,
119
Application *app = value;
121
return app->draws_attention;
125
im_application_list_update_draws_attention (ImApplicationList *list)
127
const gchar *icon_name;
129
GActionGroup *main_actions;
131
if (g_hash_table_find (list->applications, application_draws_attention, NULL))
132
icon_name = "indicator-messages-new";
134
icon_name = "indicator-messages";
136
main_actions = g_action_muxer_get_group (list->muxer, NULL);
137
state = g_variant_new ("(sssb)", "", icon_name, "Messages", TRUE);
138
g_action_group_change_action_state (main_actions, "messages", state);
141
/* Check a source action to see if it draws */
143
app_source_action_check_draw (Application * app, const gchar * action_name)
145
gboolean retval = FALSE;
149
state = g_action_group_get_action_state (G_ACTION_GROUP(app->source_actions), action_name);
152
draw = g_variant_get_child_value(state, 3);
153
retval = g_variant_get_boolean(draw);
155
g_variant_unref(draw);
156
g_variant_unref(state);
161
/* Check a message action to see if it draws */
163
app_message_action_check_draw (Application * app, const gchar * action_name)
165
GAction * action = NULL;
166
action = g_simple_action_group_lookup (app->message_actions, action_name);
167
return GPOINTER_TO_INT(g_object_get_qdata(G_OBJECT(action), message_action_draws_attention_quark()));
170
/* Regenerate the draw attention flag based on the sources and messages
171
that we have in the action groups */
173
app_check_draw_attention (Application * app)
175
gchar **source_actions = NULL;
176
gchar **message_actions = NULL;
179
source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
180
for (it = source_actions; *it && !app->draws_attention; it++)
181
app->draws_attention = app_source_action_check_draw (app, *it);
183
message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
184
for (it = message_actions; *it; it++)
185
app->draws_attention = app_message_action_check_draw (app, *it);
187
g_strfreev (source_actions);
188
g_strfreev (message_actions);
193
/* Remove a source from an application, signal up and update the status
194
of the draws attention flag. */
196
im_application_list_source_removed (Application *app,
199
g_simple_action_group_remove (app->source_actions, id);
201
g_signal_emit (app->list, signals[SOURCE_REMOVED], 0, app->id, id);
203
if (app->draws_attention)
205
app->draws_attention = FALSE;
206
app_check_draw_attention(app);
209
im_application_list_update_draws_attention (app->list);
213
im_application_list_source_activated (GSimpleAction *action,
217
Application *app = user_data;
218
const gchar *source_id;
220
source_id = g_action_get_name (G_ACTION (action));
222
if (g_variant_get_boolean (parameter))
224
indicator_messages_application_call_activate_source (app->proxy,
231
const gchar *sources[] = { source_id, NULL };
232
const gchar *messages[] = { NULL };
233
indicator_messages_application_call_dismiss (app->proxy, sources, messages,
234
app->cancellable, NULL, NULL);
237
im_application_list_source_removed (app, source_id);
241
im_application_list_message_removed (Application *app,
244
g_simple_action_group_remove (app->message_actions, id);
245
g_action_muxer_remove (app->message_sub_actions, id);
247
im_application_list_update_draws_attention (app->list);
249
g_signal_emit (app->list, signals[MESSAGE_REMOVED], 0, app->id, id);
253
im_application_list_message_activated (GSimpleAction *action,
257
Application *app = user_data;
258
const gchar *message_id;
260
message_id = g_action_get_name (G_ACTION (action));
262
if (g_variant_get_boolean (parameter))
264
indicator_messages_application_call_activate_message (app->proxy,
267
g_variant_new_array (G_VARIANT_TYPE_VARIANT, NULL, 0),
273
const gchar *sources[] = { NULL };
274
const gchar *messages[] = { message_id, NULL };
275
indicator_messages_application_call_dismiss (app->proxy, sources, messages,
276
app->cancellable, NULL, NULL);
279
im_application_list_message_removed (app, message_id);
283
im_application_list_sub_message_activated (GSimpleAction *action,
287
Application *app = user_data;
288
const gchar *message_id;
289
const gchar *action_id;
290
GVariantBuilder builder;
292
message_id = g_object_get_data (G_OBJECT (action), "message");
293
action_id = g_action_get_name (G_ACTION (action));
295
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
297
g_variant_builder_add (&builder, "v", parameter);
299
indicator_messages_application_call_activate_message (app->proxy,
302
g_variant_builder_end (&builder),
306
im_application_list_message_removed (app, message_id);
310
im_application_list_remove_all (GSimpleAction *action,
314
ImApplicationList *list = user_data;
318
g_signal_emit (list, signals[REMOVE_ALL], 0);
320
g_hash_table_iter_init (&iter, list->applications);
321
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &app))
323
gchar **source_actions;
324
gchar **message_actions;
327
app->draws_attention = FALSE;
329
source_actions = g_action_group_list_actions (G_ACTION_GROUP (app->source_actions));
330
for (it = source_actions; *it; it++)
331
im_application_list_source_removed (app, *it);
333
message_actions = g_action_group_list_actions (G_ACTION_GROUP (app->message_actions));
334
for (it = message_actions; *it; it++)
335
im_application_list_message_removed (app, *it);
337
if (app->proxy != NULL) /* If it is remote, we tell the app we've cleared */
339
indicator_messages_application_call_dismiss (app->proxy,
340
(const gchar * const *) source_actions,
341
(const gchar * const *) message_actions,
342
app->cancellable, NULL, NULL);
345
g_strfreev (source_actions);
346
g_strfreev (message_actions);
349
im_application_list_update_draws_attention (list);
353
im_application_list_dispose (GObject *object)
355
ImApplicationList *list = IM_APPLICATION_LIST (object);
357
g_clear_object (&list->statusaction);
358
g_clear_object (&list->globalactions);
359
g_clear_pointer (&list->app_status, g_hash_table_unref);
361
g_clear_pointer (&list->applications, g_hash_table_unref);
362
g_clear_object (&list->muxer);
364
G_OBJECT_CLASS (im_application_list_parent_class)->dispose (object);
368
im_application_list_finalize (GObject *object)
370
G_OBJECT_CLASS (im_application_list_parent_class)->finalize (object);
374
im_application_list_class_init (ImApplicationListClass *klass)
376
GObjectClass *object_class = G_OBJECT_CLASS (klass);
378
object_class->dispose = im_application_list_dispose;
379
object_class->finalize = im_application_list_finalize;
381
signals[SOURCE_ADDED] = g_signal_new ("source-added",
382
IM_TYPE_APPLICATION_LIST,
386
g_cclosure_marshal_generic,
394
signals[SOURCE_CHANGED] = g_signal_new ("source-changed",
395
IM_TYPE_APPLICATION_LIST,
399
g_cclosure_marshal_generic,
407
signals[SOURCE_REMOVED] = g_signal_new ("source-removed",
408
IM_TYPE_APPLICATION_LIST,
412
g_cclosure_marshal_generic,
418
signals[MESSAGE_ADDED] = g_signal_new ("message-added",
419
IM_TYPE_APPLICATION_LIST,
423
g_cclosure_marshal_generic,
437
signals[MESSAGE_REMOVED] = g_signal_new ("message-removed",
438
IM_TYPE_APPLICATION_LIST,
442
g_cclosure_marshal_generic,
448
signals[APP_ADDED] = g_signal_new ("app-added",
449
IM_TYPE_APPLICATION_LIST,
453
g_cclosure_marshal_generic,
457
G_TYPE_DESKTOP_APP_INFO);
459
signals[APP_STOPPED] = g_signal_new ("app-stopped",
460
IM_TYPE_APPLICATION_LIST,
464
g_cclosure_marshal_VOID__OBJECT,
469
signals[REMOVE_ALL] = g_signal_new ("remove-all",
470
IM_TYPE_APPLICATION_LIST,
474
g_cclosure_marshal_VOID__VOID,
478
signals[STATUS_SET] = g_signal_new ("status-set",
479
IM_TYPE_APPLICATION_LIST,
483
g_cclosure_marshal_generic,
490
im_application_list_init (ImApplicationList *list)
492
const GActionEntry action_entries[] = {
493
{ "messages", NULL, NULL, "('', 'indicator-messages', 'Messages', true)", NULL },
494
{ "remove-all", im_application_list_remove_all }
497
list->applications = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, application_free);
498
list->app_status = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
500
list->globalactions = g_simple_action_group_new ();
501
g_simple_action_group_add_entries (list->globalactions, action_entries, G_N_ELEMENTS (action_entries), list);
503
list->statusaction = g_simple_action_new_stateful("status", G_VARIANT_TYPE_STRING, g_variant_new_string("offline"));
504
g_signal_connect(list->statusaction, "activate", G_CALLBACK(status_activated), list);
505
g_simple_action_group_insert(list->globalactions, G_ACTION(list->statusaction));
507
list->muxer = g_action_muxer_new ();
508
g_action_muxer_insert (list->muxer, NULL, G_ACTION_GROUP (list->globalactions));
513
im_application_list_new (void)
515
return g_object_new (IM_TYPE_APPLICATION_LIST, NULL);
519
im_application_list_canonical_id (const gchar *id)
526
if (g_str_has_suffix (id, ".desktop"))
529
str = g_strndup (id, len);
531
for (p = str; *p; p++)
541
im_application_list_lookup (ImApplicationList *list,
542
const gchar *desktop_id)
547
id = im_application_list_canonical_id (desktop_id);
548
app = g_hash_table_lookup (list->applications, id);
555
im_application_list_activate_launch (GSimpleAction *action,
559
Application *app = user_data;
560
GError *error = NULL;
562
if (!g_app_info_launch (G_APP_INFO (app->info), NULL, NULL, &error))
564
g_warning ("unable to launch application: %s", error->message);
565
g_error_free (error);
570
im_application_list_activate_app_action (GSimpleAction *action,
574
Application *app = user_data;
576
g_desktop_app_info_launch_action (app->info, g_action_get_name (G_ACTION (action)), NULL);
580
im_application_list_add (ImApplicationList *list,
581
const gchar *desktop_id)
583
GDesktopAppInfo *info;
586
GSimpleActionGroup *actions;
587
GSimpleAction *launch_action;
589
g_return_if_fail (IM_IS_APPLICATION_LIST (list));
590
g_return_if_fail (desktop_id != NULL);
592
if (im_application_list_lookup (list, desktop_id))
595
info = g_desktop_app_info_new (desktop_id);
598
g_warning ("an application with id '%s' is not installed", desktop_id);
602
id = g_app_info_get_id (G_APP_INFO (info));
603
g_return_if_fail (id != NULL);
605
app = g_slice_new0 (Application);
607
app->id = im_application_list_canonical_id (id);
609
app->muxer = g_action_muxer_new ();
610
app->source_actions = g_simple_action_group_new ();
611
app->message_actions = g_simple_action_group_new ();
612
app->message_sub_actions = g_action_muxer_new ();
613
app->draws_attention = FALSE;
615
actions = g_simple_action_group_new ();
617
launch_action = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (FALSE));
618
g_signal_connect (launch_action, "activate", G_CALLBACK (im_application_list_activate_launch), app);
619
g_action_map_add_action (G_ACTION_MAP (actions), G_ACTION (launch_action));
622
const gchar *const *app_actions;
624
for (app_actions = g_desktop_app_info_list_actions (app->info); *app_actions; app_actions++)
626
GSimpleAction *action;
628
action = g_simple_action_new (*app_actions, NULL);
629
g_signal_connect (action, "activate", G_CALLBACK (im_application_list_activate_app_action), app);
630
g_action_map_add_action (G_ACTION_MAP (actions), G_ACTION (action));
632
g_object_unref (action);
636
g_action_muxer_insert (app->muxer, NULL, G_ACTION_GROUP (actions));
637
g_action_muxer_insert (app->muxer, "src", G_ACTION_GROUP (app->source_actions));
638
g_action_muxer_insert (app->muxer, "msg", G_ACTION_GROUP (app->message_actions));
639
g_action_muxer_insert (app->muxer, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
641
g_hash_table_insert (list->applications, (gpointer) app->id, app);
642
g_action_muxer_insert (list->muxer, app->id, G_ACTION_GROUP (app->muxer));
644
g_signal_emit (app->list, signals[APP_ADDED], 0, app->id, app->info);
646
g_object_unref (launch_action);
647
g_object_unref (actions);
651
im_application_list_remove (ImApplicationList *list,
656
g_return_if_fail (IM_IS_APPLICATION_LIST (list));
658
app = im_application_list_lookup (list, id);
661
if (app->proxy || app->cancellable)
662
g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
664
g_hash_table_remove (list->applications, id);
665
g_action_muxer_remove (list->muxer, id);
667
im_application_list_update_draws_attention (list);
672
im_application_list_source_added (Application *app,
678
const gchar *iconstr;
682
gboolean draws_attention;
684
GSimpleAction *action;
686
g_variant_get (source, "(&s&s&sux&sb)",
687
&id, &label, &iconstr, &count, &time, &string, &draws_attention);
689
state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
690
action = g_simple_action_new_stateful (id, G_VARIANT_TYPE_BOOLEAN, state);
691
g_signal_connect (action, "activate", G_CALLBACK (im_application_list_source_activated), app);
693
g_simple_action_group_insert (app->source_actions, G_ACTION (action));
695
g_signal_emit (app->list, signals[SOURCE_ADDED], 0, app->id, id, label, iconstr);
698
app->draws_attention = TRUE;
700
im_application_list_update_draws_attention (app->list);
702
g_object_unref (action);
706
im_application_list_source_changed (Application *app,
711
const gchar *iconstr;
715
gboolean draws_attention;
717
g_variant_get (source, "(&s&s&sux&sb)",
718
&id, &label, &iconstr, &count, &time, &string, &draws_attention);
720
g_action_group_change_action_state (G_ACTION_GROUP (app->source_actions), id,
721
g_variant_new ("(uxsb)", count, time, string, draws_attention));
723
g_signal_emit (app->list, signals[SOURCE_CHANGED], 0, app->id, id, label, iconstr);
725
im_application_list_update_draws_attention (app->list);
729
im_application_list_sources_listed (GObject *source_object,
730
GAsyncResult *result,
733
Application *app = user_data;
735
GError *error = NULL;
737
if (indicator_messages_application_call_list_sources_finish (app->proxy, &sources, result, &error))
743
g_variant_iter_init (&iter, sources);
744
while ((source = g_variant_iter_next_value (&iter)))
746
im_application_list_source_added (app, i++, source);
747
g_variant_unref (source);
750
g_variant_unref (sources);
754
g_warning ("could not fetch the list of sources: %s", error->message);
755
g_error_free (error);
760
get_symbolic_app_icon_string (GIcon *icon)
762
const gchar * const *names;
763
gchar *symbolic_name;
764
GIcon *symbolic_icon;
767
if (!G_IS_THEMED_ICON (icon))
770
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
771
if (!names || !names[0])
774
symbolic_icon = g_themed_icon_new_from_names ((gchar **) names, -1);
776
symbolic_name = g_strconcat (names[0], "-symbolic", NULL);
777
g_themed_icon_prepend_name (G_THEMED_ICON (symbolic_icon), symbolic_name);
779
str = g_icon_to_string (symbolic_icon);
781
g_free (symbolic_name);
782
g_object_unref (symbolic_icon);
787
im_application_list_message_added (Application *app,
791
const gchar *iconstr;
793
const gchar *subtitle;
796
GVariantIter *action_iter;
797
gboolean draws_attention;
798
GSimpleAction *action;
800
gchar *app_iconstr = NULL;
801
GVariant *actions = NULL;
803
g_variant_get (message, "(&s&s&s&s&sxaa{sv}b)",
804
&id, &iconstr, &title, &subtitle, &body, &time, &action_iter, &draws_attention);
806
app_icon = g_app_info_get_icon (G_APP_INFO (app->info));
808
app_iconstr = get_symbolic_app_icon_string (app_icon);
810
action = g_simple_action_new (id, G_VARIANT_TYPE_BOOLEAN);
811
g_object_set_qdata(G_OBJECT(action), message_action_draws_attention_quark(), GINT_TO_POINTER(draws_attention));
812
g_signal_connect (action, "activate", G_CALLBACK (im_application_list_message_activated), app);
813
g_simple_action_group_insert (app->message_actions, G_ACTION (action));
817
GSimpleActionGroup *action_group;
818
GVariantBuilder actions_builder;
820
g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
821
action_group = g_simple_action_group_new ();
823
while ((entry = g_variant_iter_next_value (action_iter)))
826
GSimpleAction *action;
828
const gchar *type = NULL;
830
GVariantBuilder dict_builder;
831
gchar *prefixed_name;
833
if (!g_variant_lookup (entry, "name", "&s", &name))
835
g_warning ("action dictionary for message '%s' is missing 'name' key", id);
839
label = g_variant_lookup_value (entry, "label", G_VARIANT_TYPE_STRING);
840
g_variant_lookup (entry, "parameter-type", "&g", &type);
841
hint = g_variant_lookup_value (entry, "parameter-hint", NULL);
843
action = g_simple_action_new (name, type ? G_VARIANT_TYPE (type) : NULL);
844
g_object_set_data_full (G_OBJECT (action), "message", g_strdup (id), g_free);
845
g_signal_connect (action, "activate", G_CALLBACK (im_application_list_sub_message_activated), app);
846
g_simple_action_group_insert (action_group, G_ACTION (action));
848
g_variant_builder_init (&dict_builder, G_VARIANT_TYPE ("a{sv}"));
850
prefixed_name = g_strjoin (".", app->id, "msg-actions", id, name, NULL);
851
g_variant_builder_add (&dict_builder, "{sv}", "name", g_variant_new_string (prefixed_name));
855
g_variant_builder_add (&dict_builder, "{sv}", "label", label);
856
g_variant_unref (label);
860
g_variant_builder_add (&dict_builder, "{sv}", "parameter-type", g_variant_new_string (type));
864
g_variant_builder_add (&dict_builder, "{sv}", "parameter-hint", hint);
865
g_variant_unref (hint);
868
g_variant_builder_add (&actions_builder, "a{sv}", &dict_builder);
870
g_object_unref (action);
871
g_variant_unref (entry);
872
g_free (prefixed_name);
875
g_action_muxer_insert (app->message_sub_actions, id, G_ACTION_GROUP (action_group));
876
actions = g_variant_builder_end (&actions_builder);
878
g_object_unref (action_group);
882
app->draws_attention = TRUE;
884
im_application_list_update_draws_attention (app->list);
886
g_signal_emit (app->list, signals[MESSAGE_ADDED], 0,
887
app->id, app_iconstr, id, iconstr, title,
888
subtitle, body, actions, time, draws_attention);
890
g_variant_iter_free (action_iter);
891
g_free (app_iconstr);
892
g_object_unref (action);
896
im_application_list_messages_listed (GObject *source_object,
897
GAsyncResult *result,
900
Application *app = user_data;
902
GError *error = NULL;
904
if (indicator_messages_application_call_list_messages_finish (app->proxy, &messages, result, &error))
909
g_variant_iter_init (&iter, messages);
910
while ((message = g_variant_iter_next_value (&iter)))
912
im_application_list_message_added (app, message);
913
g_variant_unref (message);
916
g_variant_unref (messages);
920
g_warning ("could not fetch the list of messages: %s", error->message);
921
g_error_free (error);
926
im_application_list_unset_remote (Application *app)
928
gboolean was_running;
930
was_running = app->proxy || app->cancellable;
932
if (app->cancellable)
934
g_cancellable_cancel (app->cancellable);
935
g_clear_object (&app->cancellable);
937
g_clear_object (&app->proxy);
939
/* clear actions by creating a new action group and overriding it in
941
g_object_unref (app->source_actions);
942
g_object_unref (app->message_actions);
943
g_object_unref (app->message_sub_actions);
944
app->source_actions = g_simple_action_group_new ();
945
app->message_actions = g_simple_action_group_new ();
946
app->message_sub_actions = g_action_muxer_new ();
947
g_action_muxer_insert (app->muxer, "src", G_ACTION_GROUP (app->source_actions));
948
g_action_muxer_insert (app->muxer, "msg", G_ACTION_GROUP (app->message_actions));
949
g_action_muxer_insert (app->muxer, "msg-actions", G_ACTION_GROUP (app->message_sub_actions));
951
im_application_list_update_draws_attention (app->list);
952
g_action_group_change_action_state (G_ACTION_GROUP (app->muxer), "launch", g_variant_new_boolean (FALSE));
955
g_signal_emit (app->list, signals[APP_STOPPED], 0, app->id);
959
im_application_list_app_vanished (GDBusConnection *connection,
963
Application *app = user_data;
965
im_application_list_unset_remote (app);
969
im_application_list_proxy_created (GObject *source_object,
970
GAsyncResult *result,
973
Application *app = user_data;
974
GError *error = NULL;
976
app->proxy = indicator_messages_application_proxy_new_finish (result, &error);
979
if (error->code != G_IO_ERROR_CANCELLED)
980
g_warning ("could not create application proxy: %s", error->message);
981
g_error_free (error);
985
indicator_messages_application_call_list_sources (app->proxy, app->cancellable,
986
im_application_list_sources_listed, app);
987
indicator_messages_application_call_list_messages (app->proxy, app->cancellable,
988
im_application_list_messages_listed, app);
990
g_signal_connect_swapped (app->proxy, "source-added", G_CALLBACK (im_application_list_source_added), app);
991
g_signal_connect_swapped (app->proxy, "source-changed", G_CALLBACK (im_application_list_source_changed), app);
992
g_signal_connect_swapped (app->proxy, "source-removed", G_CALLBACK (im_application_list_source_removed), app);
993
g_signal_connect_swapped (app->proxy, "message-added", G_CALLBACK (im_application_list_message_added), app);
994
g_signal_connect_swapped (app->proxy, "message-removed", G_CALLBACK (im_application_list_message_removed), app);
996
g_action_group_change_action_state (G_ACTION_GROUP (app->muxer), "launch", g_variant_new_boolean (TRUE));
998
g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (G_DBUS_PROXY (app->proxy)),
999
g_dbus_proxy_get_name (G_DBUS_PROXY (app->proxy)),
1000
G_BUS_NAME_WATCHER_FLAGS_NONE,
1001
NULL, im_application_list_app_vanished,
1006
im_application_list_set_remote (ImApplicationList *list,
1008
GDBusConnection *connection,
1009
const gchar *unique_bus_name,
1010
const gchar *object_path)
1014
g_return_if_fail (IM_IS_APPLICATION_LIST (list));
1016
app = im_application_list_lookup (list, id);
1019
g_warning ("'%s' is not a registered application", id);
1023
if (app->cancellable)
1025
gchar *name_owner = NULL;
1028
name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (app->proxy));
1029
g_warning ("replacing '%s' at %s with %s", id, name_owner, unique_bus_name);
1031
im_application_list_unset_remote (app);
1033
g_free (name_owner);
1036
app->cancellable = g_cancellable_new ();
1037
indicator_messages_application_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE,
1038
unique_bus_name, object_path, app->cancellable,
1039
im_application_list_proxy_created, app);
1043
im_application_list_get_action_group (ImApplicationList *list)
1045
g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
1047
return G_ACTION_GROUP (list->muxer);
1051
im_application_list_get_applications (ImApplicationList *list)
1053
g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
1055
return g_hash_table_get_keys (list->applications);
1059
im_application_list_get_application (ImApplicationList *list,
1064
g_return_val_if_fail (IM_IS_APPLICATION_LIST (list), NULL);
1066
app = g_hash_table_lookup (list->applications, id);
1067
return app ? app->info : NULL;
1071
status_activated (GSimpleAction * action, GVariant * param, gpointer user_data)
1073
g_return_if_fail (IM_IS_APPLICATION_LIST(user_data));
1074
ImApplicationList * list = IM_APPLICATION_LIST(user_data);
1075
const gchar * status = g_variant_get_string(param, NULL);
1077
g_simple_action_set_state(action, param);
1079
GList * appshash = g_hash_table_get_keys(list->app_status);
1080
GList * appsfree = g_list_copy_deep(appshash, (GCopyFunc)g_strdup, NULL);
1083
for (app = appsfree; app != NULL; app = g_list_next(app)) {
1084
g_hash_table_insert(list->app_status, app->data, g_strdup(status));
1087
g_list_free(appshash);
1088
g_list_free(appsfree);
1090
g_signal_emit (list, signals[STATUS_SET], 0, status);
1095
#define STATUS_ID_OFFLINE (G_N_ELEMENTS(status_ids) - 1)
1096
static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };
1099
status2val (const gchar * string)
1101
if (string == NULL) return STATUS_ID_OFFLINE;
1104
for (i = 0; i < G_N_ELEMENTS(status_ids); i++) {
1105
if (g_strcmp0(status_ids[i], string) == 0) {
1110
if (i > STATUS_ID_OFFLINE)
1111
i = STATUS_ID_OFFLINE;
1117
im_application_list_set_status (ImApplicationList * list, const gchar * id, const gchar *status)
1119
g_return_if_fail (IM_IS_APPLICATION_LIST (list));
1121
g_hash_table_insert(list->app_status, im_application_list_canonical_id(id), g_strdup(status));
1123
guint final_status = STATUS_ID_OFFLINE;
1125
GList * statuses = g_hash_table_get_values(list->app_status);
1126
GList * statusentry;
1128
for (statusentry = statuses; statusentry != NULL; statusentry = g_list_next(statusentry)) {
1129
guint statusval = status2val((gchar *)statusentry->data);
1130
final_status = MIN(final_status, statusval);
1133
g_list_free(statuses);
1135
g_simple_action_set_state(list->statusaction, g_variant_new_string(status_ids[final_status]));