aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Uebernickel <lars.uebernickel@canonical.com>2012-06-27 17:25:34 +0200
committerLars Uebernickel <lars.uebernickel@canonical.com>2012-06-27 17:25:34 +0200
commit93db8c38f2252cb4d506d90721446c0ad524ca3b (patch)
tree225d98b0f8256eeae44ed5dd92821a2096919ba2
parent1caa3be43ec40c7fb1bbb37a585555fe2526dc57 (diff)
downloadayatana-indicator-messages-93db8c38f2252cb4d506d90721446c0ad524ca3b.tar.gz
ayatana-indicator-messages-93db8c38f2252cb4d506d90721446c0ad524ca3b.tar.bz2
ayatana-indicator-messages-93db8c38f2252cb4d506d90721446c0ad524ca3b.zip
Add draws-attention flag to source actions
AppSections watch those flags for associated sources and mux them into a draws-attention property for the whole section.
-rw-r--r--libmessaging-menu/messaging-menu.c45
-rw-r--r--src/app-section.c151
-rw-r--r--src/app-section.h1
-rw-r--r--src/messages-service.c43
4 files changed, 217 insertions, 23 deletions
diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c
index d848651..eff3b4f 100644
--- a/libmessaging-menu/messaging-menu.c
+++ b/libmessaging-menu/messaging-menu.c
@@ -463,7 +463,7 @@ messaging_menu_app_insert_source_with_count (MessagingMenuApp *app,
guint count)
{
messaging_menu_app_insert_source_action (app, position, id, icon, label,
- g_variant_new ("(uxs)", count, 0, ""));
+ g_variant_new ("(uxsb)", count, 0, "", FALSE));
}
/**
@@ -517,7 +517,7 @@ messaging_menu_app_insert_source_with_time (MessagingMenuApp *app,
gint64 time)
{
messaging_menu_app_insert_source_action (app, position, id, icon, label,
- g_variant_new ("(uxs)", 0, time, ""));
+ g_variant_new ("(uxsb)", 0, time, "", FALSE));
}
/**
@@ -573,7 +573,7 @@ messaging_menu_app_insert_source_with_string (MessagingMenuApp *app,
const gchar *str)
{
messaging_menu_app_insert_source_action (app, position, id, icon, label,
- g_variant_new ("(uxs)", 0, 0, str));
+ g_variant_new ("(uxsb)", 0, 0, str, FALSE));
}
/**
@@ -673,7 +673,7 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app,
guint count)
{
messaging_menu_app_set_source_action (app, source_id,
- g_variant_new ("(uxs)", count, 0, ""));
+ g_variant_new ("(uxsb)", count, 0, "", FALSE));
}
/**
@@ -693,7 +693,7 @@ messaging_menu_app_set_source_time (MessagingMenuApp *app,
gint64 time)
{
messaging_menu_app_set_source_action (app, source_id,
- g_variant_new ("(uxs)", 0, time, ""));
+ g_variant_new ("(uxsb)", 0, time, "", FALSE));
}
/**
@@ -713,7 +713,36 @@ messaging_menu_app_set_source_string (MessagingMenuApp *app,
const gchar *str)
{
messaging_menu_app_set_source_action (app, source_id,
- g_variant_new ("(uxs)", 0, 0, str));
+ g_variant_new ("(uxsb)", 0, 0, str, FALSE));
+}
+
+static void
+messaging_menu_app_set_attention (MessagingMenuApp *app,
+ const gchar *source_id,
+ gboolean attention)
+{
+ GAction *action;
+ GVariant *state;
+ guint32 count;
+ gint64 time;
+ const gchar *str ="";
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ action = g_simple_action_group_lookup (app->source_actions, source_id);
+ if (action == NULL)
+ {
+ g_warning ("a source with id '%s' doesn't exist", source_id);
+ return;
+ }
+
+ state = g_action_get_state (action);
+ g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
+ g_variant_unref (state);
+
+ g_simple_action_set_state (G_SIMPLE_ACTION (action),
+ g_variant_new ("(uxsb)", count, time, str, attention));
}
/**
@@ -731,7 +760,7 @@ void
messaging_menu_app_draw_attention (MessagingMenuApp *app,
const gchar *source_id)
{
- g_warning ("%s: not yet implemented", G_STRFUNC);
+ messaging_menu_app_set_attention (app, source_id, TRUE);
}
/**
@@ -748,5 +777,5 @@ void
messaging_menu_app_remove_attention (MessagingMenuApp *app,
const gchar *source_id)
{
- g_warning ("%s: not yet implemented", G_STRFUNC);
+ messaging_menu_app_set_attention (app, source_id, FALSE);
}
diff --git a/src/app-section.c b/src/app-section.c
index 472fb6c..35a842f 100644
--- a/src/app-section.c
+++ b/src/app-section.c
@@ -45,6 +45,8 @@ struct _AppSectionPrivate
GMenuModel *remote_menu;
GActionGroup *actions;
+ gboolean draws_attention;
+
guint name_watch_id;
};
@@ -52,6 +54,7 @@ enum {
PROP_0,
PROP_APPINFO,
PROP_ACTIONS,
+ PROP_DRAWS_ATTENTION,
NUM_PROPERTIES
};
@@ -74,6 +77,18 @@ static void activate_cb (GSimpleAction *action,
gpointer userdata);
static void app_section_set_app_info (AppSection *self,
GDesktopAppInfo *appinfo);
+static gboolean any_action_draws_attention (GActionGroup *group,
+ const gchar *ignored_action);
+static void action_added (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data);
+static void action_state_changed (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value,
+ gpointer user_data);
+static void action_removed (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data);
/* GObject Boilerplate */
G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT);
@@ -101,6 +116,12 @@ app_section_class_init (AppSectionClass *klass)
G_TYPE_ACTION_GROUP,
G_PARAM_READABLE);
+ properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention",
+ "Draws attention",
+ "Whether the section currently draws attention",
+ FALSE,
+ G_PARAM_READABLE);
+
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
@@ -120,6 +141,8 @@ app_section_init (AppSection *self)
priv->menu = g_menu_new ();
priv->static_shortcuts = g_simple_action_group_new ();
+ priv->draws_attention = FALSE;
+
return;
}
@@ -137,6 +160,10 @@ app_section_get_property (GObject *object,
g_value_set_object (value, app_section_get_app_info (self));
break;
+ case PROP_DRAWS_ATTENTION:
+ g_value_set_boolean (value, app_section_get_draws_attention (self));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -174,7 +201,15 @@ app_section_dispose (GObject *object)
priv->name_watch_id = 0;
}
- g_clear_object (&priv->actions);
+ if (priv->actions) {
+ g_object_disconnect (priv->actions,
+ "any_signal::action-added", action_added, self,
+ "any_signal::action-state-changed", action_state_changed, self,
+ "any_signal::action-removed", action_removed, self,
+ NULL);
+ g_clear_object (&priv->actions);
+ }
+
g_clear_object (&priv->remote_menu);
if (priv->ids != NULL) {
@@ -334,6 +369,13 @@ app_section_get_app_info (AppSection *self)
return G_APP_INFO (priv->appinfo);
}
+gboolean
+app_section_get_draws_attention (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+ return priv->draws_attention;
+}
+
static void
application_vanished (GDBusConnection *bus,
const gchar *name,
@@ -367,6 +409,14 @@ app_section_set_object_path (AppSection *self,
app_section_unset_object_path (self);
priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path));
+
+ priv->draws_attention = any_action_draws_attention (priv->actions, NULL);
+ g_object_connect (priv->actions,
+ "signal::action-added", action_added, self,
+ "signal::action-state-changed", action_state_changed, self,
+ "signal::action-removed", action_removed, self,
+ NULL);
+
priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path));
g_menu_append_section (priv->menu, NULL, priv->remote_menu);
@@ -376,6 +426,7 @@ app_section_set_object_path (AppSection *self,
self, NULL);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
g_object_thaw_notify (G_OBJECT (self));
}
@@ -396,7 +447,15 @@ app_section_unset_object_path (AppSection *self)
g_bus_unwatch_name (priv->name_watch_id);
priv->name_watch_id = 0;
}
- g_clear_object (&priv->actions);
+
+ if (priv->actions) {
+ g_object_disconnect (priv->actions,
+ "any_signal::action-added", action_added, self,
+ "any_signal::action-state-changed", action_state_changed, self,
+ "any_signal::action-removed", action_removed, self,
+ NULL);
+ g_clear_object (&priv->actions);
+ }
if (priv->remote_menu) {
/* the last menu item points is linked to the app's menumodel */
@@ -405,6 +464,94 @@ app_section_unset_object_path (AppSection *self)
g_clear_object (&priv->remote_menu);
}
+ priv->draws_attention = FALSE;
+
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
}
+static gboolean
+action_draws_attention (GVariant *state)
+{
+ gboolean attention;
+
+ if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")))
+ g_variant_get_child (state, 3, "b", &attention);
+ else
+ attention = FALSE;
+
+ return attention;
+}
+
+static gboolean
+any_action_draws_attention (GActionGroup *group,
+ const gchar *ignored_action)
+{
+ gchar **actions;
+ gchar **it;
+ gboolean attention = FALSE;
+
+ actions = g_action_group_list_actions (group);
+
+ for (it = actions; *it && !attention; it++) {
+ GVariant *state;
+
+ if (ignored_action && g_str_equal (ignored_action, *it))
+ continue;
+
+ state = g_action_group_get_action_state (group, *it);
+ if (state) {
+ attention = action_draws_attention (state);
+ g_variant_unref (state);
+ }
+ }
+
+ g_strfreev (actions);
+ return attention;
+}
+
+static void
+action_added (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ GVariant *state;
+
+ state = g_action_group_get_action_state (group, action_name);
+ if (state) {
+ self->priv->draws_attention |= action_draws_attention (state);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+ g_variant_unref (state);
+ }
+}
+
+static void
+action_state_changed (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+
+ self->priv->draws_attention = any_action_draws_attention (group, NULL);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+}
+
+static void
+action_removed (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ GVariant *state;
+
+ state = g_action_group_get_action_state (group, action_name);
+ if (!state)
+ return;
+
+ self->priv->draws_attention = any_action_draws_attention (group, action_name);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+
+ g_variant_unref (state);
+}
diff --git a/src/app-section.h b/src/app-section.h
index 36e091d..935f7a2 100644
--- a/src/app-section.h
+++ b/src/app-section.h
@@ -56,6 +56,7 @@ const gchar * app_section_get_desktop (AppSection * appitem);
GActionGroup * app_section_get_actions (AppSection *self);
GMenuModel * app_section_get_menu (AppSection *appitem);
GAppInfo * app_section_get_app_info (AppSection *appitem);
+gboolean app_section_get_draws_attention (AppSection *appitem);
void app_section_set_object_path (AppSection *self,
GDBusConnection *bus,
const gchar *bus_name,
diff --git a/src/messages-service.c b/src/messages-service.c
index 8a08423..209abe5 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -73,6 +73,31 @@ actions_changed (GObject *object,
g_free (id);
}
+
+static gboolean
+app_section_draws_attention (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ AppSection *section = value;
+ return app_section_get_draws_attention (section);
+}
+
+static void
+draws_attention_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GSimpleAction *clear;
+ gboolean attention;
+
+ clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear"));
+ g_return_if_fail (clear != NULL);
+
+ attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL;
+ g_simple_action_set_enabled (clear, attention);
+}
+
static AppSection *
add_application (const gchar *desktop_id)
{
@@ -98,6 +123,8 @@ add_application (const gchar *desktop_id)
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);
/* TODO insert it at the right position (alphabetically by application name) */
menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section));
@@ -132,6 +159,9 @@ remove_application (const char *desktop_id)
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);
}
else {
g_warning ("could not remove '%s', it's not registered", desktop_id);
@@ -211,15 +241,6 @@ change_status (GSimpleAction *action,
}
static void
-clear_action_handler (MessageServiceDbus *msd,
- gboolean attention,
- gpointer user_data)
-{
- GSimpleAction *action = user_data;
- g_simple_action_set_enabled (action, attention);
-}
-
-static void
register_application (MessageServiceDbus *msd,
const gchar *sender,
const gchar *desktop_id,
@@ -336,10 +357,6 @@ main (int argc, char ** argv)
action_muxer = g_action_muxer_new ();
g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions));
- g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED,
- G_CALLBACK(clear_action_handler),
- g_action_map_lookup_action (G_ACTION_MAP (actions), "clear"));
-
g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION,
G_CALLBACK (register_application), NULL);
g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION,