aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dbus-data.h2
-rw-r--r--src/gactionmuxer.c8
-rw-r--r--src/gactionmuxer.h3
-rw-r--r--src/messages-service.c551
4 files changed, 169 insertions, 395 deletions
diff --git a/src/dbus-data.h b/src/dbus-data.h
index 64747a9..ceeb546 100644
--- a/src/dbus-data.h
+++ b/src/dbus-data.h
@@ -3,7 +3,7 @@
#define __DBUS_DATA_H__ 1
#define INDICATOR_MESSAGES_DBUS_NAME "com.canonical.indicator.messages"
-#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages/menu"
+#define INDICATOR_MESSAGES_DBUS_OBJECT "/com/canonical/indicator/messages"
#define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service"
#define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service"
diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c
index 2b1d11a..0f3cda4 100644
--- a/src/gactionmuxer.c
+++ b/src/gactionmuxer.c
@@ -483,3 +483,11 @@ g_action_muxer_remove (GActionMuxer *muxer,
g_clear_object (&muxer->global_actions);
}
+GActionGroup *
+g_action_muxer_get_group (GActionMuxer *muxer,
+ const gchar *prefix)
+{
+ g_return_val_if_fail (G_IS_ACTION_MUXER (muxer), NULL);
+
+ return prefix ? g_hash_table_lookup (muxer->groups, prefix) : muxer->global_actions;
+}
diff --git a/src/gactionmuxer.h b/src/gactionmuxer.h
index 5c5e839..caf9ec7 100644
--- a/src/gactionmuxer.h
+++ b/src/gactionmuxer.h
@@ -40,5 +40,8 @@ void g_action_muxer_insert (GActionMuxer *muxer,
void g_action_muxer_remove (GActionMuxer *muxer,
const gchar *prefix);
+GActionGroup * g_action_muxer_get_group (GActionMuxer *muxer,
+ const gchar *prefix);
+
#endif
diff --git a/src/messages-service.c b/src/messages-service.c
index b36a0a2..9d64412 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -28,12 +28,12 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <gio/gdesktopappinfo.h>
#include <glib/gi18n.h>
-#include "app-section.h"
#include "dbus-data.h"
#include "gactionmuxer.h"
#include "gsettingsstrv.h"
#include "gmenuutils.h"
#include "indicator-messages-service.h"
+#include "indicator-messages-application.h"
#define NUM_STATUSES 5
@@ -44,7 +44,8 @@ static GSimpleActionGroup *actions;
static GActionMuxer *action_muxer;
static GMenu *toplevel_menu;
static GMenu *menu;
-static GMenuModel *chat_section;
+static GMenu *messages_section;
+static GMenu *sources_section;
static GSettings *settings;
static gboolean draws_attention;
static const gchar *global_status[6]; /* max 5: available, away, busy, invisible, offline */
@@ -82,358 +83,173 @@ indicator_messages_get_icon_name ()
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)
-{
- const gchar *id;
-
- id = g_app_info_get_id (appinfo);
- if (!id)
- return NULL;
-
- if (g_str_has_suffix (id, ".desktop"))
- return g_strndup (id, strlen (id) - 8);
- else
- return g_strdup (id);
-}
-
-static void
-actions_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+static void
+service_shutdown (IndicatorService * service, gpointer user_data)
{
- AppSection *section = APP_SECTION (object);
- gchar *id;
- GActionGroup *actions;
-
- id = g_app_info_get_simple_id (app_section_get_app_info (section));
- actions = app_section_get_actions (section);
-
- g_action_muxer_insert (action_muxer, id, actions);
- g_free (id);
-}
-
+ GMainLoop *mainloop = user_data;
-static gboolean
-app_section_draws_attention (gpointer key,
- gpointer value,
- gpointer user_data)
-{
- AppSection *section = value;
- return app_section_get_draws_attention (section);
+ g_warning("Shutting down service!");
+ g_main_loop_quit(mainloop);
}
static void
-draws_attention_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- GSimpleAction *clear;
-
- clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear"));
- g_return_if_fail (clear != NULL);
-
- draws_attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL;
-
- g_simple_action_set_enabled (clear, draws_attention);
-
- indicator_messages_update_icon ();
-}
-
-static gboolean
-app_section_uses_chat (gpointer key,
- gpointer value,
+clear_action_activate (GSimpleAction *simple,
+ GVariant *param,
gpointer user_data)
{
- AppSection *section = value;
- return app_section_get_uses_chat_status (section);
+ /* TODO */
}
static void
-update_chat_section ()
+status_action_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
{
- gboolean show_chat;
- GMenuModel *first_section;
-
- show_chat = g_hash_table_find (applications, app_section_uses_chat, NULL) != NULL;
-
- first_section = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, G_MENU_LINK_SECTION);
- if (first_section == chat_section) {
- if (!show_chat)
- g_menu_remove (menu, 0);
- }
- else {
- if (show_chat)
- g_menu_insert_section (menu, 0, NULL, chat_section);
- }
+ const gchar *status;
- if (first_section != NULL)
- g_object_unref (first_section);
+ status = g_variant_get_string (parameter, NULL);
- indicator_messages_update_icon ();
+ indicator_messages_service_emit_status_changed (messages_service, status);
}
static void
-uses_chat_status_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+sources_listed (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- 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;
-}
+ gchar *app_id = 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;
-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))
+ if (!indicator_messages_application_call_list_sources_finish (INDICATOR_MESSAGES_APPLICATION (source_object),
+ &sources, result, &error))
{
- 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)
-{
- int pos = g_menu_find_section (menu, app_section_get_menu (section));
- if (pos >= 0)
- g_menu_remove (menu, pos);
- g_action_muxer_remove (action_muxer, id);
-
- 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);
-
- if (g_hash_table_size (applications) == 0 &&
- g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 1) {
- g_menu_remove (toplevel_menu, 0);
- }
-
- update_chat_status ();
- update_chat_section ();
-}
-
-static AppSection *
-add_application (const gchar *desktop_id)
-{
- GDesktopAppInfo *appinfo;
- gchar *id;
- AppSection *section;
-
- appinfo = g_desktop_app_info_new (desktop_id);
- if (!appinfo) {
- g_warning ("could not add '%s', there's no desktop file with that id", desktop_id);
- return NULL;
- }
-
- id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
- section = g_hash_table_lookup (applications, id);
-
- if (!section) {
- GMenuItem *menuitem;
-
- section = app_section_new(appinfo);
- g_hash_table_insert (applications, g_strdup (id), section);
-
- g_action_muxer_insert (action_muxer, id, app_section_get_actions (section));
- g_signal_connect (section, "notify::actions",
- G_CALLBACK (actions_changed), NULL);
- g_signal_connect (section, "notify::draws-attention",
- 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),
- (GClosureNotify) g_free,
- 0);
-
- /* TODO insert it at the right position (alphabetically by application name) */
- menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section));
- g_menu_item_set_attribute (menuitem, "action-namespace", "s", id);
- g_menu_insert_item (menu, g_menu_model_get_n_items (G_MENU_MODEL (menu)) -1, menuitem);
- g_object_unref (menuitem);
+ g_warning ("could not fetch the list of sources: %s", error->message);
+ g_error_free (error);
+ g_free (app_id);
+ return;
}
- if (g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 0) {
- GMenuItem *header;
-
- 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-accessible-description", "s", _("Messages"));
- g_menu_append_item (toplevel_menu, header);
-
- g_object_unref (header);
+ g_variant_iter_init (&iter, sources);
+ while (g_variant_iter_next (&iter, "(&s&s&sux&sb)", &id, &label, &iconstr, &count,
+ &time, &string, &draws_attention))
+ {
+ GMenuItem *item;
+ GActionGroup *app_actions;
+ GSimpleAction *action;
+ gchar *action_name;
+
+ app_actions = g_action_muxer_get_group (action_muxer, app_id);
+ 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));
+
+ action_name = g_strconcat (app_id, ".", id, NULL);
+ item = g_menu_item_new (label, action_name);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.sourceitem");
+ if (iconstr && *iconstr)
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
+ g_menu_append_item (sources_section, item);
+
+ g_object_unref (action);
+ g_free (action_name);
+ g_object_unref (item);
}
- g_free (id);
- g_object_unref (appinfo);
- return section;
+ g_variant_unref (sources);
+ g_free (app_id);
}
static void
-remove_application (const char *desktop_id)
+messages_listed (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GDesktopAppInfo *appinfo;
- gchar *id;
- AppSection *section;
-
- appinfo = g_desktop_app_info_new (desktop_id);
- if (!appinfo) {
- g_warning ("could not remove '%s', there's no desktop file with that id", desktop_id);
+ gchar *app_id = 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_free (app_id);
return;
}
- id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
-
- section = g_hash_table_lookup (applications, id);
- if (section) {
- remove_section (section, id);
- }
- else {
- g_warning ("could not remove '%s', it's not registered", desktop_id);
- }
-
- g_free (id);
- g_object_unref (appinfo);
-}
-
-/* This function turns a specific desktop id into a menu
- item and registers it appropriately with everyone */
-static gboolean
-build_launcher (gpointer data)
-{
- gchar *desktop_id = data;
-
- add_application (desktop_id);
-
- g_free (desktop_id);
- return FALSE;
-}
-
-/* This function goes through all the launchers that we're
- supposed to be grabbing and decides to show turn them
- into menu items or not. It doens't do the work, but it
- makes the decision. */
-static gboolean
-build_launchers (gpointer data)
-{
- gchar **applications = g_settings_get_strv (settings, "applications");
- gchar **app;
-
- g_return_val_if_fail (applications != NULL, FALSE);
-
- for (app = applications; *app; app++)
+ 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))
{
- g_idle_add(build_launcher, g_strdup (*app));
+ GMenuItem *item;
+ GActionGroup *app_actions;
+ GSimpleAction *action;
+ gchar *action_name;
+
+ app_actions = g_action_muxer_get_group (action_muxer, app_id);
+ 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));
+
+ action_name = g_strconcat (app_id, ".", id, NULL);
+ item = g_menu_item_new (NULL, action_name);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.messageitem");
+ g_menu_item_set_attribute (item, "x-canonical-message-id", "s", id);
+ g_menu_item_set_attribute (item, "x-canonical-sender", "s", title);
+ g_menu_item_set_attribute (item, "x-canonical-subject", "s", subtitle);
+ g_menu_item_set_attribute (item, "x-canonical-body", "s", body);
+ g_menu_item_set_attribute (item, "x-canonical-time", "x", time);
+ if (iconstr && *iconstr)
+ g_menu_item_set_attribute (item, "x-canonical-avatar", "s", iconstr);
+ g_menu_append_item (messages_section, item);
+
+ g_object_unref (action);
+ g_free (action_name);
+ g_object_unref (item);
}
- g_strfreev (applications);
- return FALSE;
-}
-
-static void
-service_shutdown (IndicatorService * service, gpointer user_data)
-{
- GMainLoop *mainloop = user_data;
-
- g_warning("Shutting down service!");
- g_main_loop_quit(mainloop);
+ g_variant_unref (messages);
+ g_free (app_id);
}
static void
-app_section_remove_attention (gpointer key,
- gpointer value,
- gpointer user_data)
+app_proxy_created (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- AppSection *section = value;
- app_section_clear_draws_attention (section);
-}
-
-static void
-clear_action_activate (GSimpleAction *simple,
- GVariant *param,
- gpointer user_data)
-{
- g_hash_table_foreach (applications, app_section_remove_attention, NULL);
-}
+ gchar *desktop_id = user_data;
+ IndicatorMessagesApplication *app_proxy;
+ GError *error = NULL;
-static void
-status_action_activate (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
-{
- const gchar *status;
+ 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;
+ }
- status = g_variant_get_string (parameter, NULL);
+ /* hash table takes ownership of desktop_id and app_proxy */
+ g_hash_table_insert (applications, desktop_id, app_proxy);
- indicator_messages_service_emit_status_changed (messages_service, status);
+ indicator_messages_application_call_list_sources (app_proxy, NULL, sources_listed, g_strdup (desktop_id));
+ indicator_messages_application_call_list_messages (app_proxy, NULL, messages_listed, g_strdup (desktop_id));
}
static void
@@ -443,21 +259,33 @@ register_application (IndicatorMessagesService *service,
const gchar *menu_path,
gpointer user_data)
{
- AppSection *section;
GDBusConnection *bus;
const gchar *sender;
+ GSimpleActionGroup *app_actions;
- section = add_application (desktop_id);
- if (!section)
+ 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;
+ }
bus = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (service));
sender = g_dbus_method_invocation_get_sender (invocation);
- app_section_set_object_path (section, bus, sender, menu_path);
+ indicator_messages_application_proxy_new (bus, G_DBUS_PROXY_FLAGS_NONE,
+ sender, menu_path, NULL,
+ app_proxy_created, g_strdup (desktop_id));
+
+ app_actions = g_simple_action_group_new ();
+ g_action_muxer_insert (action_muxer, desktop_id, G_ACTION_GROUP (app_actions));
+
g_settings_strv_append_unique (settings, "applications", desktop_id);
indicator_messages_service_complete_register_application (service, invocation);
+
+ g_object_unref (app_actions);
}
static void
@@ -466,44 +294,15 @@ unregister_application (IndicatorMessagesService *service,
const gchar *desktop_id,
gpointer user_data)
{
- remove_application (desktop_id);
- g_settings_strv_remove (settings, "applications", desktop_id);
+ if (g_hash_table_remove (applications, desktop_id)) {
- indicator_messages_service_complete_unregister_application (service, invocation);
-}
+ /* TODO remove menu items that refer to this application */
+ g_action_muxer_remove (action_muxer, desktop_id);
-static void
-set_status (IndicatorMessagesService *service,
- GDBusMethodInvocation *invocation,
- const gchar *desktop_id,
- const gchar *status_str,
- gpointer user_data)
-{
- GDesktopAppInfo *appinfo;
- gchar *id;
- AppSection *section;
-
- 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"));
-
- 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;
+ g_settings_strv_remove (settings, "applications", desktop_id);
}
- 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);
+ indicator_messages_service_complete_unregister_application (service, invocation);
}
static GSimpleActionGroup *
@@ -539,40 +338,6 @@ create_action_group (void)
return actions;
}
-static GMenuModel *
-create_status_section (void)
-{
- GMenu *menu;
- GMenuItem *item;
- struct status_item {
- gchar *label;
- gchar *action;
- gchar *icon_name;
- } status_items[] = {
- { _("Available"), "status::available", "user-available" },
- { _("Away"), "status::away", "user-away" },
- { _("Busy"), "status::busy", "user-busy" },
- { _("Invisible"), "status::invisible", "user-invisible" },
- { _("Offline"), "status::offline", "user-offline" }
- };
- int i;
-
- menu = g_menu_new ();
-
- item = g_menu_item_new (NULL, NULL);
- g_menu_item_set_attribute (item, "x-canonical-type", "s", "IdoMenuItem");
-
- for (i = 0; i < G_N_ELEMENTS (status_items); i++) {
- g_menu_item_set_label (item, status_items[i].label);
- g_menu_item_set_detailed_action (item, status_items[i].action);
- g_menu_item_set_attribute (item, "x-canonical-icon", "s", status_items[i].icon_name);
- g_menu_append_item (menu, item);
- }
-
- g_object_unref (item);
- return G_MENU_MODEL (menu);
-}
-
static void
got_bus (GObject *object,
GAsyncResult * res,
@@ -596,7 +361,7 @@ got_bus (GObject *object,
return;
}
- g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT,
+ g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT "/phone",
G_MENU_MODEL (toplevel_menu), &error);
if (error) {
g_warning ("unable to export menu on dbus: %s", error->message);
@@ -651,26 +416,24 @@ main (int argc, char ** argv)
G_CALLBACK (register_application), NULL);
g_signal_connect (messages_service, "handle-unregister-application",
G_CALLBACK (unregister_application), NULL);
- g_signal_connect (messages_service, "handle-set-status",
- G_CALLBACK (set_status), NULL);
menu = g_menu_new ();
- chat_section = create_status_section ();
- g_menu_append (menu, _("Clear"), "clear");
+ sources_section = g_menu_new ();
+ messages_section = g_menu_new ();
+ g_menu_append_section (menu, NULL, G_MENU_MODEL (sources_section));
+ g_menu_append_section (menu, NULL, G_MENU_MODEL (messages_section));
toplevel_menu = g_menu_new ();
+ g_menu_append_submenu (toplevel_menu, NULL, G_MENU_MODEL (menu));
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);
- g_idle_add(build_launchers, NULL);
-
g_main_loop_run(mainloop);
/* Clean up */
g_object_unref (messages_service);
- g_object_unref (chat_section);
g_object_unref (settings);
g_hash_table_unref (applications);
return 0;