aboutsummaryrefslogtreecommitdiff
path: root/src/messages-service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/messages-service.c')
-rw-r--r--src/messages-service.c215
1 files changed, 151 insertions, 64 deletions
diff --git a/src/messages-service.c b/src/messages-service.c
index fd0bdcb..73f3d35 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -35,15 +35,63 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "gmenuutils.h"
#include "indicator-messages-service.h"
+#define NUM_STATUSES 5
+
static GHashTable *applications;
-IndicatorMessagesService *messages_service;
+static IndicatorMessagesService *messages_service;
static GSimpleActionGroup *actions;
static GActionMuxer *action_muxer;
static GMenu *toplevel_menu;
static GMenu *menu;
static GMenuModel *chat_section;
static GSettings *settings;
+static gboolean draws_attention;
+static const gchar *global_status[6]; /* max 5: available, away, busy, invisible, offline */
+
+static gchar *
+indicator_messages_get_icon_name ()
+{
+ GString *name;
+ GIcon *icon;
+ gchar *iconstr;
+
+ name = g_string_new ("indicator-messages");
+
+ if (global_status[0] != NULL)
+ {
+ if (global_status[1] != NULL)
+ g_string_append (name, "-mixed");
+ else
+ g_string_append_printf (name, "-%s", global_status[0]);
+ }
+
+ if (draws_attention)
+ g_string_append (name, "-new");
+
+ icon = g_themed_icon_new (name->str);
+ iconstr = g_icon_to_string (icon);
+
+ g_object_unref (icon);
+ g_string_free (name, TRUE);
+
+ return iconstr;
+}
+
+static void
+indicator_messages_update_icon ()
+{
+ GSimpleAction *messages;
+ gchar *icon;
+
+ messages = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "messages"));
+ g_return_if_fail (messages != NULL);
+
+ icon = indicator_messages_get_icon_name ();
+ g_simple_action_set_state (messages, g_variant_new_string (icon));
+
+ g_free (icon);
+}
static gchar *
g_app_info_get_simple_id (GAppInfo *appinfo)
@@ -91,18 +139,16 @@ draws_attention_changed (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
- GSimpleAction *messages;
GSimpleAction *clear;
- gboolean attention;
- messages = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "messages"));
clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear"));
- g_return_if_fail (messages != NULL && clear != NULL);
+ g_return_if_fail (clear != NULL);
+
+ draws_attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL;
- attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL;
+ g_simple_action_set_enabled (clear, draws_attention);
- g_simple_action_set_state (messages, g_variant_new_boolean (attention));
- g_simple_action_set_enabled (clear, attention);
+ indicator_messages_update_icon ();
}
static gboolean
@@ -134,6 +180,8 @@ update_chat_section ()
if (first_section != NULL)
g_object_unref (first_section);
+
+ indicator_messages_update_icon ();
}
static void
@@ -144,6 +192,61 @@ uses_chat_status_changed (GObject *object,
update_chat_section ();
}
+static gboolean
+strv_contains (const gchar **strv,
+ const gchar *needle)
+{
+ const gchar **it;
+
+ it = strv;
+ while (*it != NULL && !g_str_equal (*it, needle))
+ it++;
+
+ return *it != NULL;
+}
+
+static void
+update_chat_status ()
+{
+ GHashTableIter iter;
+ AppSection *section;
+ int pos;
+ GAction *status;
+
+ for (pos = 0; pos < G_N_ELEMENTS (global_status); pos++)
+ global_status[pos] = NULL;
+
+ pos = 0;
+ g_hash_table_iter_init (&iter, applications);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer) &section) &&
+ pos < G_N_ELEMENTS (global_status))
+ {
+ const gchar *status_str = NULL;
+
+ status_str = app_section_get_status (section);
+ if (status_str != NULL && !strv_contains (global_status, status_str))
+ global_status[pos++] = status_str;
+ }
+
+ if (pos == 0)
+ global_status[0] = "offline";
+
+ status = g_simple_action_group_lookup (actions, "status");
+ g_return_if_fail (status != NULL);
+
+ g_simple_action_set_state (G_SIMPLE_ACTION (status), g_variant_new_strv (global_status, -1));
+
+ indicator_messages_update_icon ();
+}
+
+static void
+chat_status_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ update_chat_status ();
+}
+
static void
remove_section (AppSection *section,
const gchar *id)
@@ -156,6 +259,7 @@ remove_section (AppSection *section,
g_signal_handlers_disconnect_by_func (section, actions_changed, NULL);
g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL);
g_signal_handlers_disconnect_by_func (section, uses_chat_status_changed, NULL);
+ g_signal_handlers_disconnect_by_func (section, chat_status_changed, NULL);
g_signal_handlers_disconnect_by_func (section, remove_section, NULL);
g_hash_table_remove (applications, id);
@@ -165,6 +269,7 @@ remove_section (AppSection *section,
g_menu_remove (toplevel_menu, 0);
}
+ update_chat_status ();
update_chat_section ();
}
@@ -197,6 +302,8 @@ add_application (const gchar *desktop_id)
G_CALLBACK (draws_attention_changed), NULL);
g_signal_connect (section, "notify::uses-chat-status",
G_CALLBACK (uses_chat_status_changed), NULL);
+ g_signal_connect (section, "notify::chat-status",
+ G_CALLBACK (chat_status_changed), NULL);
g_signal_connect_data (section, "destroy",
G_CALLBACK (remove_section),
g_strdup (id),
@@ -212,21 +319,13 @@ add_application (const gchar *desktop_id)
if (g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 0) {
GMenuItem *header;
- GIcon *icon;
- gchar *iconstr;
-
- icon = g_themed_icon_new ("indicator-messages");
- iconstr = g_icon_to_string (icon);
header = g_menu_item_new (NULL, "messages");
g_menu_item_set_submenu (header, G_MENU_MODEL (menu));
- g_menu_item_set_attribute (header, "x-canonical-icon", "s", iconstr);
g_menu_item_set_attribute (header, "x-canonical-accessible-description", "s", _("Messages"));
g_menu_append_item (toplevel_menu, header);
g_object_unref (header);
- g_free (iconstr);
- g_object_unref (icon);
}
g_free (id);
@@ -322,48 +421,15 @@ clear_action_activate (GSimpleAction *simple,
}
static void
-radio_item_activate (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- g_action_change_state (G_ACTION (action), parameter);
-}
-
-static gboolean
-g_action_state_equal (GAction *action,
- GVariant *value)
-{
- GVariant *state;
- gboolean eq;
-
- state = g_action_get_state (action);
- g_return_val_if_fail (state != NULL, FALSE);
-
- eq = g_variant_equal (state, value);
-
- g_variant_unref (state);
- return eq;
-}
-
-static void
-change_status_action (GSimpleAction *action,
- GVariant *value,
- gpointer user_data)
+status_action_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
const gchar *status;
- g_variant_get (value, "&s", &status);
+ status = g_variant_get_string (parameter, NULL);
- g_return_if_fail (g_str_equal (status, "available") ||
- g_str_equal (status, "away")||
- g_str_equal (status, "busy") ||
- g_str_equal (status, "invisible") ||
- g_str_equal (status, "offline"));
-
- if (!g_action_state_equal (G_ACTION (action), value)) {
- g_simple_action_set_state (action, value);
- indicator_messages_service_emit_status_changed (messages_service, status);
- }
+ indicator_messages_service_emit_status_changed (messages_service, status);
}
static void
@@ -405,17 +471,35 @@ unregister_application (IndicatorMessagesService *service,
static void
set_status (IndicatorMessagesService *service,
GDBusMethodInvocation *invocation,
+ const gchar *desktop_id,
const gchar *status_str,
gpointer user_data)
{
- GAction *status;
+ GDesktopAppInfo *appinfo;
+ gchar *id;
+ AppSection *section;
- status = g_simple_action_group_lookup (actions, "status");
- g_return_if_fail (status != NULL);
+ g_return_if_fail (g_str_equal (status_str, "available") ||
+ g_str_equal (status_str, "away")||
+ g_str_equal (status_str, "busy") ||
+ g_str_equal (status_str, "invisible") ||
+ g_str_equal (status_str, "offline"));
- g_action_change_state (status, g_variant_new_string (status_str));
+ appinfo = g_desktop_app_info_new (desktop_id);
+ if (!appinfo) {
+ g_warning ("could not set status for '%s', there's no desktop file with that id", desktop_id);
+ return;
+ }
+
+ id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
+ section = g_hash_table_lookup (applications, id);
+ if (section != NULL)
+ app_section_set_status (section, status_str);
indicator_messages_service_complete_set_status (service, invocation);
+
+ g_free (id);
+ g_object_unref (appinfo);
}
static GSimpleActionGroup *
@@ -425,17 +509,19 @@ create_action_group (void)
GSimpleAction *messages;
GSimpleAction *clear;
GSimpleAction *status;
+ const gchar *default_status[] = { "offline", NULL };
+ gchar *icon;
actions = g_simple_action_group_new ();
- /* state of the messages action mirrors "draws-attention" */
- messages = g_simple_action_new_stateful ("messages", G_VARIANT_TYPE ("b"),
- g_variant_new_boolean (FALSE));
+ /* state of the messages action is its icon name */
+ icon = indicator_messages_get_icon_name ();
+ messages = g_simple_action_new_stateful ("messages", G_VARIANT_TYPE ("s"),
+ g_variant_new_string (icon));
status = g_simple_action_new_stateful ("status", G_VARIANT_TYPE ("s"),
- g_variant_new ("s", "offline"));
- g_signal_connect (status, "activate", G_CALLBACK (radio_item_activate), NULL);
- g_signal_connect (status, "change-state", G_CALLBACK (change_status_action), NULL);
+ g_variant_new_strv (default_status, -1));
+ g_signal_connect (status, "activate", G_CALLBACK (status_action_activate), NULL);
clear = g_simple_action_new ("clear", NULL);
g_simple_action_set_enabled (clear, FALSE);
@@ -445,6 +531,7 @@ create_action_group (void)
g_simple_action_group_insert (actions, G_ACTION (status));
g_simple_action_group_insert (actions, G_ACTION (clear));
+ g_free (icon);
return actions;
}