From d7bba03dd7712cf2a5c60c4e99967525fbaab778 Mon Sep 17 00:00:00 2001 From: Pete Woods Date: Tue, 20 Aug 2013 11:25:22 +0100 Subject: Thunderbird e-mail notifications work again (forward ported fix from r344) --- src/im-desktop-menu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/im-desktop-menu.c b/src/im-desktop-menu.c index 1040d62..ac480e1 100644 --- a/src/im-desktop-menu.c +++ b/src/im-desktop-menu.c @@ -114,7 +114,8 @@ im_desktop_menu_source_added (ImApplicationList *applist, g_return_if_fail (source_section != NULL); action = g_strconcat ("src.", source_id, NULL); - item = g_menu_item_new (label, action); + item = g_menu_item_new (label, NULL); + g_menu_item_set_action_and_target_value(item, action, NULL); g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.messages.source"); if (icon && *icon) g_menu_item_set_attribute (item, "icon", "s", icon); -- cgit v1.2.3 From 9f67d20d20f68e9512908c3f24ed79d85f120358 Mon Sep 17 00:00:00 2001 From: Pete Woods Date: Tue, 20 Aug 2013 12:57:16 +0100 Subject: "Clear" and "Clear All" now translatable --- src/im-desktop-menu.c | 2 +- src/im-phone-menu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/im-desktop-menu.c b/src/im-desktop-menu.c index ac480e1..e68d086 100644 --- a/src/im-desktop-menu.c +++ b/src/im-desktop-menu.c @@ -228,7 +228,7 @@ im_desktop_menu_constructed (GObject *object) GMenu *clear_section; clear_section = g_menu_new (); - g_menu_append (clear_section, "Clear", "indicator.remove-all"); + g_menu_append (clear_section, _("Clear"), "indicator.remove-all"); im_menu_append_section (IM_MENU (menu), G_MENU_MODEL (clear_section)); g_object_unref (clear_section); diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c index 7381097..843060d 100644 --- a/src/im-phone-menu.c +++ b/src/im-phone-menu.c @@ -72,7 +72,7 @@ im_phone_menu_constructed (GObject *object) clear_section = g_menu_new (); - item = g_menu_item_new ("Clear All", "remove-all"); + item = g_menu_item_new (_("Clear All"), "remove-all"); g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.button"); g_menu_append_item (clear_section, item); -- cgit v1.2.3 From 0d5c6bf1e1fa56fcd562a66493f1123c2904f2b0 Mon Sep 17 00:00:00 2001 From: Pete Woods Date: Tue, 20 Aug 2013 15:00:35 +0100 Subject: Compile again --- src/im-phone-menu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/im-phone-menu.c b/src/im-phone-menu.c index 843060d..0ea6f76 100644 --- a/src/im-phone-menu.c +++ b/src/im-phone-menu.c @@ -20,6 +20,7 @@ #include "im-phone-menu.h" #include +#include typedef ImMenuClass ImPhoneMenuClass; -- cgit v1.2.3 From b929a0f22e0835b519be7b1811214dbcce40d0b2 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 09:39:27 -0500 Subject: Track the old draw_attention and look for updates --- src/im-application-list.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index bba7972..39e10e7 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -713,15 +713,21 @@ im_application_list_source_changed (Application *app, gint64 time; const gchar *string; gboolean draws_attention; + gboolean old_draw; g_variant_get (source, "(&s&s&sux&sb)", &id, &label, &iconstr, &count, &time, &string, &draws_attention); + old_draw = app_source_action_check_draw(app, id); + 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); + if (!old_draw && draws_attention) + app->draws_attention = TRUE; + im_application_list_update_draws_attention (app->list); } -- cgit v1.2.3 From 4626ffb3b99b9db6868751c18b9080563301b7fd Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 09:43:58 -0500 Subject: Make the accessible name translatable and based on the blue envelope --- src/im-application-list.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index 39e10e7..a2775ff 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -25,6 +25,8 @@ #include #include +#include "glib/gi18n.h" + typedef GObjectClass ImApplicationListClass; struct _ImApplicationList @@ -125,16 +127,20 @@ static void im_application_list_update_draws_attention (ImApplicationList *list) { const gchar *icon_name; + const gchar *accessible_name; GVariant *state; GActionGroup *main_actions; - if (g_hash_table_find (list->applications, application_draws_attention, NULL)) + if (g_hash_table_find (list->applications, application_draws_attention, NULL)) { icon_name = "indicator-messages-new"; - else + accessible_name = _("New Messages"); + } else { icon_name = "indicator-messages"; + accessible_name = _("Messages"); + } main_actions = g_action_muxer_get_group (list->muxer, NULL); - state = g_variant_new ("(sssb)", "", icon_name, "Messages", TRUE); + state = g_variant_new ("(sssb)", "", icon_name, accessible_name, TRUE); g_action_group_change_action_state (main_actions, "messages", state); } -- cgit v1.2.3 From 5ed5380d4624446c47e5f77d7bc114cb42fd2b95 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 10:56:05 -0500 Subject: Making the base menu item an a{sv} with proper icons and fallbacks --- src/im-application-list.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index a2775ff..e4b697f 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -126,22 +126,45 @@ application_draws_attention (gpointer key, static void im_application_list_update_draws_attention (ImApplicationList *list) { - const gchar *icon_name; + const gchar *base_icon_name; const gchar *accessible_name; + const gchar *icon_name; + GIcon * icon; + GVariantBuilder builder; GVariant *state; - GActionGroup *main_actions; if (g_hash_table_find (list->applications, application_draws_attention, NULL)) { - icon_name = "indicator-messages-new"; + base_icon_name = "indicator-messages-new-%s"; accessible_name = _("New Messages"); } else { - icon_name = "indicator-messages"; + base_icon_name = "indicator-messages-%s"; accessible_name = _("Messages"); } - main_actions = g_action_muxer_get_group (list->muxer, NULL); - state = g_variant_new ("(sssb)", "", icon_name, accessible_name, TRUE); - g_action_group_change_action_state (main_actions, "messages", state); + state = g_action_group_get_action_state(G_ACTION_GROUP(list->globalactions), "status"); + icon_name = g_strdup_printf(base_icon_name, g_variant_get_string(state, NULL)); + g_variant_unref(state); + + g_variant_builder_init(&builder, G_VARIANT_TYPE_DICTIONARY); + + g_variant_builder_open(&builder, G_VARIANT_TYPE_DICT_ENTRY); + g_variant_builder_add_value(&builder, g_variant_new_string("icon")); + icon = g_themed_icon_new_with_default_fallbacks(icon_name); + g_variant_builder_add_value(&builder, g_variant_new_variant(g_icon_serialize(icon))); + g_object_unref(icon); + g_variant_builder_close(&builder); + + g_variant_builder_open(&builder, G_VARIANT_TYPE_DICT_ENTRY); + g_variant_builder_add_value(&builder, g_variant_new_string("accessible-desc")); + g_variant_builder_add_value(&builder, g_variant_new_variant(g_variant_new_string(accessible_name))); + g_variant_builder_close(&builder); + + g_variant_builder_open(&builder, G_VARIANT_TYPE_DICT_ENTRY); + g_variant_builder_add_value(&builder, g_variant_new_string("visible")); + g_variant_builder_add_value(&builder, g_variant_new_variant(g_variant_new_boolean(TRUE))); + g_variant_builder_close(&builder); + + g_action_group_change_action_state (G_ACTION_GROUP(list->globalactions), "messages", g_variant_builder_end(&builder)); } /* Check a source action to see if it draws */ @@ -496,7 +519,6 @@ 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 } }; @@ -504,6 +526,10 @@ im_application_list_init (ImApplicationList *list) 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 (); + { + GSimpleAction * messages = g_simple_action_new_stateful("messages", G_VARIANT_TYPE("a{sv}"), g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0)); + g_simple_action_group_insert(list->globalactions, G_ACTION(messages)); + } 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")); @@ -513,6 +539,7 @@ im_application_list_init (ImApplicationList *list) list->muxer = g_action_muxer_new (); g_action_muxer_insert (list->muxer, NULL, G_ACTION_GROUP (list->globalactions)); + im_application_list_update_draws_attention (list); } ImApplicationList * @@ -1101,6 +1128,8 @@ status_activated (GSimpleAction * action, GVariant * param, gpointer user_data) g_signal_emit (list, signals[STATUS_SET], 0, status); + im_application_list_update_draws_attention(list); + return; } @@ -1146,6 +1175,8 @@ im_application_list_set_status (ImApplicationList * list, const gchar * id, cons g_simple_action_set_state(list->statusaction, g_variant_new_string(status_ids[final_status])); + im_application_list_update_draws_attention(list); + return; } -- cgit v1.2.3 From 7dda565d32554b5414f813b88df343b3b0256878 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 11:31:19 -0500 Subject: Stealing the desktop shortcuts from libindicator --- src/Makefile.am | 4 +- src/indicator-desktop-shortcuts.c | 680 ++++++++++++++++++++++++++++++++++++++ src/indicator-desktop-shortcuts.h | 80 +++++ 3 files changed, 763 insertions(+), 1 deletion(-) create mode 100644 src/indicator-desktop-shortcuts.c create mode 100644 src/indicator-desktop-shortcuts.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e03406a..9b1cc9a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,9 @@ indicator_messages_service_SOURCES = \ im-desktop-menu.c \ im-desktop-menu.h \ im-application-list.c \ - im-application-list.h + im-application-list.h \ + indicator-desktop-shortcuts.c \ + indicator-desktop-shortcuts.h indicator_messages_service_CFLAGS = \ $(APPLET_CFLAGS) \ diff --git a/src/indicator-desktop-shortcuts.c b/src/indicator-desktop-shortcuts.c new file mode 100644 index 0000000..7b43630 --- /dev/null +++ b/src/indicator-desktop-shortcuts.c @@ -0,0 +1,680 @@ +/* +A small file to parse through the actions that are available +in the desktop file and making those easily usable. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 3.0 as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License version 3.0 for more details. + +You should have received a copy of the GNU General Public +License along with this library. If not, see +. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "indicator-desktop-shortcuts.h" + +#define ACTIONS_KEY "Actions" +#define ACTION_GROUP_PREFIX "Desktop Action" + +#define OLD_GROUP_SUFFIX "Shortcut Group" +#define OLD_SHORTCUTS_KEY "X-Ayatana-Desktop-Shortcuts" +#define OLD_ENVIRON_KEY "TargetEnvironment" + +#define PROP_DESKTOP_FILE_S "desktop-file" +#define PROP_IDENTITY_S "identity" + +typedef enum _actions_t actions_t; +enum _actions_t { + ACTIONS_NONE, + ACTIONS_XAYATANA, + ACTIONS_DESKTOP_SPEC +}; + +typedef struct _IndicatorDesktopShortcutsPrivate IndicatorDesktopShortcutsPrivate; +struct _IndicatorDesktopShortcutsPrivate { + actions_t actions; + GKeyFile * keyfile; + gchar * identity; + GArray * nicks; + gchar * domain; +}; + +enum { + PROP_0, + PROP_DESKTOP_FILE, + PROP_IDENTITY +}; + +#define INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsPrivate)) + +static void indicator_desktop_shortcuts_class_init (IndicatorDesktopShortcutsClass *klass); +static void indicator_desktop_shortcuts_init (IndicatorDesktopShortcuts *self); +static void indicator_desktop_shortcuts_dispose (GObject *object); +static void indicator_desktop_shortcuts_finalize (GObject *object); +static void set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static void get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); +static void parse_keyfile (IndicatorDesktopShortcuts * ids); +static gboolean should_show (GKeyFile * keyfile, const gchar * group, const gchar * identity, gboolean should_have_target); + +G_DEFINE_TYPE (IndicatorDesktopShortcuts, indicator_desktop_shortcuts, G_TYPE_OBJECT); + +/* Build up the class */ +static void +indicator_desktop_shortcuts_class_init (IndicatorDesktopShortcutsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (IndicatorDesktopShortcutsPrivate)); + + object_class->dispose = indicator_desktop_shortcuts_dispose; + object_class->finalize = indicator_desktop_shortcuts_finalize; + + /* Property funcs */ + object_class->set_property = set_property; + object_class->get_property = get_property; + + g_object_class_install_property(object_class, PROP_DESKTOP_FILE, + g_param_spec_string(PROP_DESKTOP_FILE_S, + "The path of the desktop file to read", + "A path to a desktop file that we'll look for shortcuts in.", + NULL, + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property(object_class, PROP_IDENTITY, + g_param_spec_string(PROP_IDENTITY_S, + "The string that represents the identity that we're acting as.", + "Used to process ShowIn and NotShownIn fields of the desktop shortcust to get the proper list.", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); + + return; +} + +/* Initialize instance data */ +static void +indicator_desktop_shortcuts_init (IndicatorDesktopShortcuts *self) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(self); + + priv->keyfile = NULL; + priv->identity = NULL; + priv->domain = NULL; + priv->nicks = g_array_new(TRUE, TRUE, sizeof(gchar *)); + priv->actions = ACTIONS_NONE; + + return; +} + +/* Clear object references */ +static void +indicator_desktop_shortcuts_dispose (GObject *object) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + if (priv->keyfile) { + g_key_file_free(priv->keyfile); + priv->keyfile = NULL; + } + + G_OBJECT_CLASS (indicator_desktop_shortcuts_parent_class)->dispose (object); + return; +} + +/* Free all memory */ +static void +indicator_desktop_shortcuts_finalize (GObject *object) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + if (priv->identity != NULL) { + g_free(priv->identity); + priv->identity = NULL; + } + + if (priv->domain != NULL) { + g_free(priv->domain); + priv->domain = NULL; + } + + if (priv->nicks != NULL) { + gint i; + for (i = 0; i < priv->nicks->len; i++) { + gchar * nick = g_array_index(priv->nicks, gchar *, i); + g_free(nick); + } + g_array_free(priv->nicks, TRUE); + priv->nicks = NULL; + } + + G_OBJECT_CLASS (indicator_desktop_shortcuts_parent_class)->finalize (object); + return; +} + +/* Sets one of the two properties we have, only at construction though */ +static void +set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + g_return_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(object)); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + switch(prop_id) { + case PROP_DESKTOP_FILE: { + if (priv->keyfile != NULL) { + g_key_file_free(priv->keyfile); + priv->keyfile = NULL; + priv->actions = ACTIONS_NONE; + } + + GError * error = NULL; + GKeyFile * keyfile = g_key_file_new(); + g_key_file_load_from_file(keyfile, g_value_get_string(value), G_KEY_FILE_NONE, &error); + + if (error != NULL) { + g_warning("Unable to load keyfile from file '%s': %s", g_value_get_string(value), error->message); + g_error_free(error); + g_key_file_free(keyfile); + break; + } + + /* Always prefer the desktop spec if we can get it */ + if (priv->actions == ACTIONS_NONE && g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, ACTIONS_KEY, NULL)) { + priv->actions = ACTIONS_DESKTOP_SPEC; + } + + /* But fallback if we can't */ + if (priv->actions == ACTIONS_NONE && g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, OLD_SHORTCUTS_KEY, NULL)) { + priv->actions = ACTIONS_XAYATANA; + g_warning("Desktop file '%s' is using a deprecated format for its actions that will be dropped soon.", g_value_get_string(value)); + } + + if (priv->actions == ACTIONS_NONE) { + g_key_file_free(keyfile); + break; + } + + priv->keyfile = keyfile; + parse_keyfile(INDICATOR_DESKTOP_SHORTCUTS(object)); + break; + } + case PROP_IDENTITY: + if (priv->identity != NULL) { + g_warning("Identity already set to '%s' and trying to set it to '%s'.", priv->identity, g_value_get_string(value)); + return; + } + priv->identity = g_value_dup_string(value); + parse_keyfile(INDICATOR_DESKTOP_SHORTCUTS(object)); + break; + /* *********************** */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +/* Gets either the desktop file our the identity. */ +static void +get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ + g_return_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(object)); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + switch(prop_id) { + case PROP_IDENTITY: + g_value_set_string(value, priv->identity); + break; + /* *********************** */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +/* Checks to see if we can, and if we can it goes through + and parses the keyfile entries. */ +static void +parse_keyfile (IndicatorDesktopShortcuts * ids) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + + if (priv->keyfile == NULL) { + return; + } + + if (priv->identity == NULL) { + return; + } + + /* Remove a previous translation domain if we had one + from a previously parsed file. */ + if (priv->domain != NULL) { + g_free(priv->domain); + priv->domain = NULL; + } + + /* Check to see if there is a custom translation domain that + we should take into account. */ + if (priv->domain == NULL && + g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL)) { + priv->domain = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL); + } + + if (priv->domain == NULL && + g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, "X-Ubuntu-Gettext-Domain", NULL)) { + priv->domain = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, "X-Ubuntu-Gettext-Domain", NULL); + } + + /* We need to figure out what we're looking for and what we want to + look for in the rest of the file */ + const gchar * list_name = NULL; + const gchar * group_format = NULL; + gboolean should_have_target = FALSE; + + switch (priv->actions) { + case ACTIONS_NONE: + /* None, let's just get outta here */ + return; + case ACTIONS_XAYATANA: + list_name = OLD_SHORTCUTS_KEY; + group_format = "%s " OLD_GROUP_SUFFIX; + should_have_target = TRUE; + break; + case ACTIONS_DESKTOP_SPEC: + list_name = ACTIONS_KEY; + group_format = ACTION_GROUP_PREFIX " %s"; + should_have_target = FALSE; + break; + default: + g_assert_not_reached(); + return; + } + + /* Okay, we've got everything we need. Let's get it on! */ + gint i; + gsize num_nicks = 0; + gchar ** nicks = g_key_file_get_string_list(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, list_name, &num_nicks, NULL); + + /* If there is an error from get_string_list num_nicks should still + be zero, so this loop will drop out. */ + for (i = 0; i < num_nicks; i++) { + /* g_debug("Looking at group nick %s", nicks[i]); */ + gchar * groupname = g_strdup_printf(group_format, nicks[i]); + if (!g_key_file_has_group(priv->keyfile, groupname)) { + g_warning("Unable to find group '%s'", groupname); + g_free(groupname); + continue; + } + + if (!should_show(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, priv->identity, FALSE)) { + g_free(groupname); + continue; + } + + if (!should_show(priv->keyfile, groupname, priv->identity, should_have_target)) { + g_free(groupname); + continue; + } + + gchar * nickalloc = g_strdup(nicks[i]); + g_array_append_val(priv->nicks, nickalloc); + g_free(groupname); + } + + if (nicks != NULL) { + g_strfreev(nicks); + } + + return; +} + +/* Checks the ONLY_SHOW_IN and NOT_SHOW_IN keys for a group to + see if we should be showing ourselves. */ +static gboolean +should_show (GKeyFile * keyfile, const gchar * group, const gchar * identity, gboolean should_have_target) +{ + if (should_have_target && g_key_file_has_key(keyfile, group, OLD_ENVIRON_KEY, NULL)) { + /* If we've got this key, we're going to return here and not + process the deprecated keys. */ + gint j; + gsize num_env = 0; + gchar ** envs = g_key_file_get_string_list(keyfile, group, OLD_ENVIRON_KEY, &num_env, NULL); + + for (j = 0; j < num_env; j++) { + if (g_strcmp0(envs[j], identity) == 0) { + break; + } + } + + if (envs != NULL) { + g_strfreev(envs); + } + + if (j == num_env) { + return FALSE; + } + return TRUE; + } + + /* If there is a list of OnlyShowIn entries we need to check + to see if we're in that list. If not, we drop this nick */ + if (g_key_file_has_key(keyfile, group, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, NULL)) { + gint j; + gsize num_only = 0; + gchar ** onlies = g_key_file_get_string_list(keyfile, group, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, &num_only, NULL); + + for (j = 0; j < num_only; j++) { + if (g_strcmp0(onlies[j], identity) == 0) { + break; + } + } + + if (onlies != NULL) { + g_strfreev(onlies); + } + + if (j == num_only) { + return FALSE; + } + } + + /* If there is a NotShowIn entry we need to make sure that we're + not in that list. If we are, we need to drop out. */ + if (g_key_file_has_key(keyfile, group, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, NULL)) { + gint j; + gsize num_not = 0; + gchar ** nots = g_key_file_get_string_list(keyfile, group, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, &num_not, NULL); + + for (j = 0; j < num_not; j++) { + if (g_strcmp0(nots[j], identity) == 0) { + break; + } + } + + if (nots != NULL) { + g_strfreev(nots); + } + + if (j != num_not) { + return FALSE; + } + } + + return TRUE; +} + +/* Looks through the nicks to see if this one is in the list, + and thus valid to use. */ +static gboolean +is_valid_nick (gchar ** list, const gchar * nick) +{ + if (*list == NULL) + return FALSE; + /* g_debug("Checking Nick: %s", list[0]); */ + if (g_strcmp0(list[0], nick) == 0) + return TRUE; + return is_valid_nick(&list[1], nick); +} + +/* API */ + +/** + indicator_desktop_shortcuts_new: + @file: The desktop file that would be opened to + find the actions. + @identity: This is a string that represents the identity + that should be used in searching those actions. It + relates to the ShowIn and NotShownIn properties. + + This function creates the basic object. It involves opening + the file and parsing it. It could potentially block on IO. At + the end of the day you'll have a fully functional object. + + Return value: A new #IndicatorDesktopShortcuts object. +*/ +IndicatorDesktopShortcuts * +indicator_desktop_shortcuts_new (const gchar * file, const gchar * identity) +{ + GObject * obj = g_object_new(INDICATOR_TYPE_DESKTOP_SHORTCUTS, + PROP_DESKTOP_FILE_S, file, + PROP_IDENTITY_S, identity, + NULL); + return INDICATOR_DESKTOP_SHORTCUTS(obj); +} + +/** + indicator_desktop_shortcuts_get_nicks: + @ids: The #IndicatorDesktopShortcuts object to look in + + Give you the list of commands that are available for this desktop + file given the identity that was passed in at creation. This will + filter out the various items in the desktop file. These nicks can + then be used as keys for working with the desktop file. + + Return value: A #NULL terminated list of strings. This memory + is managed by the @ids object. +*/ +const gchar ** +indicator_desktop_shortcuts_get_nicks (IndicatorDesktopShortcuts * ids) +{ + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), NULL); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + return (const gchar **)priv->nicks->data; +} + +/** + indicator_desktop_shortcuts_nick_get_name: + @ids: The #IndicatorDesktopShortcuts object to look in + @nick: Which command that we're referencing. + + This function looks in a desktop file for a nick to find the + user visible name for that shortcut. The @nick parameter + should be gotten from #indicator_desktop_shortcuts_get_nicks + though it's not required that the exact memory location + be the same. + + Return value: A user visible string for the shortcut or + #NULL on error. +*/ +gchar * +indicator_desktop_shortcuts_nick_get_name (IndicatorDesktopShortcuts * ids, const gchar * nick) +{ + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), NULL); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + + g_return_val_if_fail(priv->actions != ACTIONS_NONE, NULL); + g_return_val_if_fail(priv->keyfile != NULL, NULL); + g_return_val_if_fail(is_valid_nick((gchar **)priv->nicks->data, nick), NULL); + + const gchar * group_format = NULL; + + switch (priv->actions) { + case ACTIONS_XAYATANA: + group_format = "%s " OLD_GROUP_SUFFIX; + break; + case ACTIONS_DESKTOP_SPEC: + group_format = ACTION_GROUP_PREFIX " %s"; + break; + default: + g_assert_not_reached(); + return NULL; + } + + gchar * groupheader = g_strdup_printf(group_format, nick); + if (!g_key_file_has_group(priv->keyfile, groupheader)) { + g_warning("The group for nick '%s' doesn't exist anymore.", nick); + g_free(groupheader); + return NULL; + } + + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_NAME, NULL)) { + g_warning("No name available for nick '%s'", nick); + g_free(groupheader); + return NULL; + } + + gchar * name = NULL; + gchar * keyvalue = g_key_file_get_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_NAME, + NULL); + gchar * localeval = g_key_file_get_locale_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_NAME, + NULL, + NULL); + g_free(groupheader); + + if (priv->domain != NULL && g_strcmp0(keyvalue, localeval) == 0) { + name = g_strdup(g_dgettext(priv->domain, keyvalue)); + g_free(localeval); + } else { + name = localeval; + } + + g_free(keyvalue); + + return name; +} + +/** + indicator_desktop_shortcuts_nick_exec_with_context: + @ids: The #IndicatorDesktopShortcuts object to look in + @nick: Which command that we're referencing. + @launch_context: The #GAppLaunchContext to use for launching the shortcut + + Here we take a @nick and try and execute the action that is + associated with it. The @nick parameter should be gotten + from #indicator_desktop_shortcuts_get_nicks though it's not + required that the exact memory location be the same. + + Return value: #TRUE on success or #FALSE on error. +*/ +gboolean +indicator_desktop_shortcuts_nick_exec_with_context (IndicatorDesktopShortcuts * ids, const gchar * nick, GAppLaunchContext * launch_context) +{ + GError * error = NULL; + + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), FALSE); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + + g_return_val_if_fail(priv->actions != ACTIONS_NONE, FALSE); + g_return_val_if_fail(priv->keyfile != NULL, FALSE); + g_return_val_if_fail(is_valid_nick((gchar **)priv->nicks->data, nick), FALSE); + + const gchar * group_format = NULL; + + switch (priv->actions) { + case ACTIONS_XAYATANA: + group_format = "%s " OLD_GROUP_SUFFIX; + break; + case ACTIONS_DESKTOP_SPEC: + group_format = ACTION_GROUP_PREFIX " %s"; + break; + default: + g_assert_not_reached(); + return FALSE; + } + + gchar * groupheader = g_strdup_printf(group_format, nick); + if (!g_key_file_has_group(priv->keyfile, groupheader)) { + g_warning("The group for nick '%s' doesn't exist anymore.", nick); + g_free(groupheader); + return FALSE; + } + + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_NAME, NULL)) { + g_warning("No name available for nick '%s'", nick); + g_free(groupheader); + return FALSE; + } + + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL)) { + g_warning("No exec available for nick '%s'", nick); + g_free(groupheader); + return FALSE; + } + + /* Grab the name and the exec entries out of our current group */ + gchar * name = g_key_file_get_locale_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_NAME, + NULL, + NULL); + + gchar * exec = g_key_file_get_locale_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_EXEC, + NULL, + NULL); + + g_free(groupheader); + + GAppInfoCreateFlags flags = G_APP_INFO_CREATE_NONE; + + if (launch_context) { + flags |= G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION; + } + + GAppInfo * appinfo = g_app_info_create_from_commandline(exec, name, flags, &error); + g_free(name); g_free(exec); + + if (error != NULL) { + g_warning("Unable to build Command line App info: %s", error->message); + g_error_free(error); + return FALSE; + } + + if (appinfo == NULL) { + g_warning("Unable to build Command line App info (unknown)"); + return FALSE; + } + + gboolean launched = g_app_info_launch(appinfo, NULL, launch_context, &error); + + if (error != NULL) { + g_warning("Unable to launch file from nick '%s': %s", nick, error->message); + g_clear_error(&error); + } + + g_object_unref(appinfo); + + return launched; +} + +/** + indicator_desktop_shortcuts_nick_exec: + @ids: The #IndicatorDesktopShortcuts object to look in + @nick: Which command that we're referencing. + + Here we take a @nick and try and execute the action that is + associated with it. The @nick parameter should be gotten + from #indicator_desktop_shortcuts_get_nicks though it's not + required that the exact memory location be the same. + This function is deprecated and shouldn't be used in newly + written code. + + Return value: #TRUE on success or #FALSE on error. +*/ +gboolean +indicator_desktop_shortcuts_nick_exec (IndicatorDesktopShortcuts * ids, const gchar * nick) +{ + return indicator_desktop_shortcuts_nick_exec_with_context (ids, nick, NULL); +} diff --git a/src/indicator-desktop-shortcuts.h b/src/indicator-desktop-shortcuts.h new file mode 100644 index 0000000..fb997ea --- /dev/null +++ b/src/indicator-desktop-shortcuts.h @@ -0,0 +1,80 @@ +/* +A small file to parse through the actions that are available +in the desktop file and making those easily usable. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 3.0 as published by the Free Software Foundation. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License version 3.0 for more details. + +You should have received a copy of the GNU General Public +License along with this library. If not, see +. +*/ + +#ifndef __INDICATOR_DESKTOP_SHORTCUTS_H__ +#define __INDICATOR_DESKTOP_SHORTCUTS_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DESKTOP_SHORTCUTS (indicator_desktop_shortcuts_get_type ()) +#define INDICATOR_DESKTOP_SHORTCUTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcuts)) +#define INDICATOR_DESKTOP_SHORTCUTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsClass)) +#define INDICATOR_IS_DESKTOP_SHORTCUTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS)) +#define INDICATOR_IS_DESKTOP_SHORTCUTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_TYPE_DESKTOP_SHORTCUTS)) +#define INDICATOR_DESKTOP_SHORTCUTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsClass)) + +typedef struct _IndicatorDesktopShortcuts IndicatorDesktopShortcuts; +typedef struct _IndicatorDesktopShortcutsClass IndicatorDesktopShortcutsClass; + +/** + IndicatorDesktopShortcutsClass: + @parent_class: Space for #GObjectClass + + The vtable for our precious #IndicatorDesktopShortcutsClass. +*/ +struct _IndicatorDesktopShortcutsClass { + GObjectClass parent_class; +}; + +/** + IndicatorDesktopShortcuts: + @parent: The parent data from #GObject + + The public data for an instance of the class + #IndicatorDesktopShortcuts. +*/ +struct _IndicatorDesktopShortcuts { + GObject parent; +}; + +GType indicator_desktop_shortcuts_get_type (void); +IndicatorDesktopShortcuts * indicator_desktop_shortcuts_new (const gchar * file, + const gchar * identity); +const gchar ** indicator_desktop_shortcuts_get_nicks (IndicatorDesktopShortcuts * ids); +gchar * indicator_desktop_shortcuts_nick_get_name (IndicatorDesktopShortcuts * ids, + const gchar * nick); +gboolean indicator_desktop_shortcuts_nick_exec_with_context (IndicatorDesktopShortcuts * ids, + const gchar * nick, + GAppLaunchContext * launch_context); + +GLIB_DEPRECATED_FOR(indicator_desktop_shortcuts_nick_exec_with_context) +gboolean indicator_desktop_shortcuts_nick_exec (IndicatorDesktopShortcuts * ids, + const gchar * nick); + +G_END_DECLS + +#endif -- cgit v1.2.3 From 8d53c7137915c36f6d1e7c11112da64c23228d17 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 15:51:55 -0500 Subject: Remove unused struct member --- src/im-application-list.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index e4b697f..6b4c33d 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -68,7 +68,6 @@ typedef struct gchar *id; IndicatorMessagesApplication *proxy; GActionMuxer *muxer; - GSimpleActionGroup *actions; GSimpleActionGroup *source_actions; GSimpleActionGroup *message_actions; GActionMuxer *message_sub_actions; -- cgit v1.2.3 From 47ecc8ff09e32d6dd20f55a4d31a5d6b91dd89da Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 15:59:35 -0500 Subject: Building up a shortcuts object to track the shortcuts from the desktop file --- src/im-application-list.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index 6b4c33d..81fee9a 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -21,6 +21,7 @@ #include "indicator-messages-application.h" #include "gactionmuxer.h" +#include "indicator-desktop-shortcuts.h" #include #include @@ -73,6 +74,7 @@ typedef struct GActionMuxer *message_sub_actions; GCancellable *cancellable; gboolean draws_attention; + IndicatorDesktopShortcuts * shortcuts; } Application; @@ -109,6 +111,8 @@ application_free (gpointer data) g_object_unref (app->message_sub_actions); } + g_clear_object (&app->shortcuts); + g_slice_free (Application, app); } @@ -617,6 +621,7 @@ im_application_list_add (ImApplicationList *list, const gchar *id; GSimpleActionGroup *actions; GSimpleAction *launch_action; + IndicatorDesktopShortcuts * shortcuts = NULL; g_return_if_fail (IM_IS_APPLICATION_LIST (list)); g_return_if_fail (desktop_id != NULL); @@ -634,6 +639,12 @@ im_application_list_add (ImApplicationList *list, id = g_app_info_get_id (G_APP_INFO (info)); g_return_if_fail (id != NULL); + { + const char * filename = g_desktop_app_info_get_filename(info); + if (filename != NULL) + shortcuts = indicator_desktop_shortcuts_new(filename, "Messaging Menu"); + } + app = g_slice_new0 (Application); app->info = info; app->id = im_application_list_canonical_id (id); @@ -643,6 +654,7 @@ im_application_list_add (ImApplicationList *list, app->message_actions = g_simple_action_group_new (); app->message_sub_actions = g_action_muxer_new (); app->draws_attention = FALSE; + app->shortcuts = shortcuts; actions = g_simple_action_group_new (); -- cgit v1.2.3 From 0bd953b0ca74c8ae50b8eb907b081d61cc8bad10 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 16:04:51 -0500 Subject: Switch to looking in the shortcuts object to set the actions --- src/im-application-list.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index 81fee9a..61d0f53 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -609,7 +609,7 @@ im_application_list_activate_app_action (GSimpleAction *action, { Application *app = user_data; - g_desktop_app_info_launch_action (app->info, g_action_get_name (G_ACTION (action)), NULL); + indicator_desktop_shortcuts_nick_exec_with_context (app->shortcuts, g_action_get_name (G_ACTION (action)), NULL); } void @@ -662,14 +662,14 @@ im_application_list_add (ImApplicationList *list, 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; + if (app->shortcuts != NULL) { + const gchar ** nicks; - for (app_actions = g_desktop_app_info_list_actions (app->info); *app_actions; app_actions++) + for (nicks = indicator_desktop_shortcuts_get_nicks (app->shortcuts); *nicks; nicks++) { GSimpleAction *action; - action = g_simple_action_new (*app_actions, NULL); + action = g_simple_action_new (*nicks, 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)); -- cgit v1.2.3 From 3f6abe759b6976d606f97b894c02b68e1c0d9254 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 16:16:34 -0500 Subject: Putting shortcuts into the menu --- src/im-desktop-menu.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/im-desktop-menu.c b/src/im-desktop-menu.c index e68d086..3309dad 100644 --- a/src/im-desktop-menu.c +++ b/src/im-desktop-menu.c @@ -18,6 +18,7 @@ */ #include "im-desktop-menu.h" +#include "indicator-desktop-shortcuts.h" #include typedef ImMenuClass ImDesktopMenuClass; @@ -66,21 +67,28 @@ im_desktop_menu_app_added (ImApplicationList *applist, } /* application actions */ -#if 0 { - const gchar *const *actions; + const gchar * filename = NULL; + IndicatorDesktopShortcuts * shortcuts = NULL; + const gchar ** nicks = {NULL}; - for (actions = g_desktop_app_info_list_actions (app_info); *actions; actions++) - { - gchar *label; + filename = g_desktop_app_info_get_filename(app_info); + if (filename != NULL) + shortcuts = indicator_desktop_shortcuts_new(filename, "Messaging Menu"); - label = g_desktop_app_info_get_action_name (app_info, *actions); - g_menu_append (app_section, label, *actions); + if (shortcuts != NULL) + for (nicks = indicator_desktop_shortcuts_get_nicks(shortcuts); *nicks; nicks++) + { + gchar *label; - g_free (label); - } + label = indicator_desktop_shortcuts_nick_get_name (shortcuts, *nicks); + g_menu_append (app_section, label, *nicks); + + g_free (label); + } + + g_clear_object(&shortcuts); } -#endif source_section = g_menu_new (); -- cgit v1.2.3 From 4d6aeed8706bb67e884e9df4bca8a78e2edba014 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 16:21:16 -0500 Subject: Adding in a sigterm handler --- src/messages-service.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/messages-service.c b/src/messages-service.c index 71fa09b..0eec2ad 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -25,6 +25,7 @@ with this program. If not, see . #include #include #include +#include #include "dbus-data.h" #include "gsettingsstrv.h" @@ -169,6 +170,16 @@ on_name_lost (GDBusConnection *bus, g_main_loop_quit (mainloop); } +static gboolean +sig_term_handler (gpointer user_data) +{ + GMainLoop *mainloop = user_data; + + g_main_loop_quit (mainloop); + + return FALSE; +} + int main (int argc, char ** argv) { @@ -225,6 +236,8 @@ main (int argc, char ** argv) g_hash_table_insert (menus, "phone", im_phone_menu_new (applications)); g_hash_table_insert (menus, "desktop", im_desktop_menu_new (applications)); + g_unix_signal_add(SIGTERM, sig_term_handler, mainloop); + g_main_loop_run(mainloop); /* Clean up */ -- cgit v1.2.3 From b526ee7d9de53067a295f9cdb9bc23fa1054492f Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 16:57:23 -0500 Subject: Enabling and disabling the remove-all action if we have items to remove --- src/im-application-list.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'src') diff --git a/src/im-application-list.c b/src/im-application-list.c index 61d0f53..b599b85 100644 --- a/src/im-application-list.c +++ b/src/im-application-list.c @@ -116,6 +116,34 @@ application_free (gpointer data) g_slice_free (Application, app); } +/* Check to see if we have actions by getting the full list of + names and see if there is one. Not exactly efficient :-/ */ +static gboolean +_g_action_group_has_actions (GActionGroup * ag) +{ + gchar ** list = NULL; + gboolean retval = FALSE; + + list = g_action_group_list_actions(ag); + retval = (list[0] != NULL); + g_strfreev(list); + + return retval; +} + +/* Check to see if either of our action groups has any actions, if + so return TRUE so we get chosen! */ +static gboolean +application_has_items (gpointer key, + gpointer value, + gpointer user_data) +{ + Application *app = value; + + return _g_action_group_has_actions(G_ACTION_GROUP(app->source_actions)) || + _g_action_group_has_actions(G_ACTION_GROUP(app->message_actions)); +} + static gboolean application_draws_attention (gpointer key, gpointer value, @@ -136,6 +164,7 @@ im_application_list_update_draws_attention (ImApplicationList *list) GVariantBuilder builder; GVariant *state; + /* Figure out what type of icon we should be drawing */ if (g_hash_table_find (list->applications, application_draws_attention, NULL)) { base_icon_name = "indicator-messages-new-%s"; accessible_name = _("New Messages"); @@ -144,12 +173,15 @@ im_application_list_update_draws_attention (ImApplicationList *list) accessible_name = _("Messages"); } + /* Include the IM state in the icon */ state = g_action_group_get_action_state(G_ACTION_GROUP(list->globalactions), "status"); icon_name = g_strdup_printf(base_icon_name, g_variant_get_string(state, NULL)); g_variant_unref(state); + /* Build up the dictionary of values for the state */ g_variant_builder_init(&builder, G_VARIANT_TYPE_DICTIONARY); + /* icon */ g_variant_builder_open(&builder, G_VARIANT_TYPE_DICT_ENTRY); g_variant_builder_add_value(&builder, g_variant_new_string("icon")); icon = g_themed_icon_new_with_default_fallbacks(icon_name); @@ -157,17 +189,29 @@ im_application_list_update_draws_attention (ImApplicationList *list) g_object_unref(icon); g_variant_builder_close(&builder); + /* accessible description */ g_variant_builder_open(&builder, G_VARIANT_TYPE_DICT_ENTRY); g_variant_builder_add_value(&builder, g_variant_new_string("accessible-desc")); g_variant_builder_add_value(&builder, g_variant_new_variant(g_variant_new_string(accessible_name))); g_variant_builder_close(&builder); + /* visibility */ g_variant_builder_open(&builder, G_VARIANT_TYPE_DICT_ENTRY); g_variant_builder_add_value(&builder, g_variant_new_string("visible")); g_variant_builder_add_value(&builder, g_variant_new_variant(g_variant_new_boolean(TRUE))); g_variant_builder_close(&builder); + /* Set the state */ g_action_group_change_action_state (G_ACTION_GROUP(list->globalactions), "messages", g_variant_builder_end(&builder)); + + GAction * remove_action = g_simple_action_group_lookup(list->globalactions, "remove-all"); + if (g_hash_table_find (list->applications, application_has_items, NULL)) { + g_debug("Enabling remove-all"); + g_simple_action_set_enabled(G_SIMPLE_ACTION(remove_action), TRUE); + } else { + g_debug("Disabling remove-all"); + g_simple_action_set_enabled(G_SIMPLE_ACTION(remove_action), FALSE); + } } /* Check a source action to see if it draws */ -- cgit v1.2.3 From 046f655a8859e2e3eaa6015fc2ecd226c8b46b1f Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 20 Aug 2013 21:03:18 -0500 Subject: Make it so that we sort based on application name to make the menu more sane --- src/im-desktop-menu.c | 2 +- src/im-menu.c | 15 +++++++++++---- src/im-menu.h | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/im-desktop-menu.c b/src/im-desktop-menu.c index 3309dad..834a8c9 100644 --- a/src/im-desktop-menu.c +++ b/src/im-desktop-menu.c @@ -97,7 +97,7 @@ im_desktop_menu_app_added (ImApplicationList *applist, g_menu_append_section (section, NULL, G_MENU_MODEL (source_section)); namespace = g_strconcat ("indicator.", app_id, NULL); - im_menu_insert_section (IM_MENU (menu), -1, namespace, G_MENU_MODEL (section)); + im_menu_insert_section (IM_MENU (menu), g_app_info_get_name(G_APP_INFO(app_info)), namespace, G_MENU_MODEL (section)); g_hash_table_insert (menu->source_sections, g_strdup (app_id), source_section); g_free (namespace); diff --git a/src/im-menu.c b/src/im-menu.c index ac23a29..1aaffe3 100644 --- a/src/im-menu.c +++ b/src/im-menu.c @@ -164,10 +164,11 @@ im_menu_append_section (ImMenu *menu, void im_menu_insert_section (ImMenu *menu, - gint position, + const gchar *sort_string, const gchar *namespace, GMenuModel *section) { + int position; ImMenuPrivate *priv; GMenuItem *item; @@ -176,11 +177,17 @@ im_menu_insert_section (ImMenu *menu, priv = im_menu_get_instance_private (menu); - /* count from the back if position is < 0 */ - if (position < 0) - position = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu)) + position; + for (position = 1; position < g_menu_model_get_n_items(G_MENU_MODEL (priv->menu)) - 1; position++) + { + gchar * item_sort = NULL; + if (g_menu_model_get_item_attribute(G_MENU_MODEL(priv->menu), position, "x-messaging-menu-sort-string", "s", &item_sort)) + if (g_utf8_collate(sort_string, item_sort) < 0) + break; + g_free(item_sort); + } item = g_menu_item_new_section (NULL, section); + g_menu_item_set_attribute (item, "x-messaging-menu-sort-string", "s", sort_string); if (namespace) g_menu_item_set_attribute (item, "action-namespace", "s", namespace); diff --git a/src/im-menu.h b/src/im-menu.h index d3775ad..7c15eb7 100644 --- a/src/im-menu.h +++ b/src/im-menu.h @@ -57,7 +57,7 @@ void im_menu_append_section (ImMenu GMenuModel *section); void im_menu_insert_section (ImMenu *menu, - gint position, + const gchar *sort_string, const gchar *namespace, GMenuModel *section); -- cgit v1.2.3