diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index fd4759669..6b2279e48 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -237,7 +237,7 @@ AppDisplay.prototype = { this._redisplayMenus(); })); this._appMonitor.connect('changed', Lang.bind(this, function(monitor) { - this._redisplay(false) + this._redisplay(false); })); // Load the GAppInfos now so it doesn't slow down the first @@ -345,6 +345,18 @@ AppDisplay.prototype = { } }, + addApp: function(appId) { + let appInfo = Gio.DesktopAppInfo.new(appId); + if (appInfo != null) { + this._allItems[appId] = appInfo; + // [] is returned if we could not get the categories or the list of categories was empty + let categories = Shell.get_categories_for_desktop_file(appId); + this._appCategories[appId] = categories; + } else { + log("appInfo for " + appId + " was not found."); + } + }, + //// Protected method overrides //// // Gets information about all applications by calling Gio.app_info_get_all(). @@ -357,19 +369,25 @@ AppDisplay.prototype = { this._menus = this._appSystem.get_menus(); - let apps = Gio.app_info_get_all(); - for (let i = 0; i < apps.length; i++) { - let appInfo = apps[i]; - - if (!appInfo.should_show()) - continue; - - let appId = appInfo.get_id(); - this._allItems[appId] = appInfo; - // [] is returned if we could not get the categories or the list of categories was empty - let categories = Shell.get_categories_for_desktop_file(appId); - this._appCategories[appId] = categories; + // Loop over the toplevel menu items, load the set of desktop file ids + // associated with each one + for (let i = 0; i < this._menus.length; i++) { + let menu = this._menus[i]; + let menuApps = this._appSystem.get_applications_for_menu(menu.id); + for (let j = 0; j < menuApps.length; j++) { + let appId = menuApps[j]; + this._addApp(appId); + } } + + // Now grab the desktop file ids for settings/preferences. + // These show up in search, but not with the rest of apps. + let settings = this._appSystem.get_all_settings(); + for (let i = 0; i < settings.length; i++) { + let appId = settings[i]; + this._addApp(appId); + } + this._appsStale = false; }, @@ -459,10 +477,12 @@ AppDisplay.prototype = { // we expect this._appCategories.hasOwnProperty(itemInfo.get_id()) to always be true here let categories = this._appCategories[itemInfo.get_id()]; - for (let i = 0; i < categories.length; i++) { - let category = categories[i].toLowerCase(); - if (category.indexOf(search) >= 0) - return true; + if (categories) { + for (let i = 0; i < categories.length; i++) { + let category = categories[i].toLowerCase(); + if (category.indexOf(search) >= 0) + return true; + } } return false; diff --git a/src/shell-app-system.c b/src/shell-app-system.c index 022d0e75a..882938922 100644 --- a/src/shell-app-system.c +++ b/src/shell-app-system.c @@ -20,10 +20,12 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _ShellAppSystemPrivate { - GMenuTree *tree; - GMenuTreeDirectory *trunk; + GMenuTree *apps_tree; + GMenuTree *settings_tree; - GList *cached_menus; + GSList *cached_app_menus; /* ShellAppMenuEntry */ + + GSList *cached_setting_ids; /* utf8 */ }; static void shell_app_system_finalize (GObject *object); @@ -81,11 +83,11 @@ shell_app_system_init (ShellAppSystem *self) SHELL_TYPE_APP_SYSTEM, ShellAppSystemPrivate); - priv->tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_NONE); + priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_NONE); + priv->settings_tree = gmenu_tree_lookup ("settings.menu", GMENU_TREE_FLAGS_NONE); - priv->trunk = gmenu_tree_get_root_directory (priv->tree); - - gmenu_tree_add_monitor (priv->tree, on_tree_changed, self); + gmenu_tree_add_monitor (priv->apps_tree, on_tree_changed, self); + gmenu_tree_add_monitor (priv->settings_tree, on_tree_changed, self); reread_menus (self); } @@ -96,23 +98,37 @@ shell_app_system_finalize (GObject *object) ShellAppSystem *self = SHELL_APP_SYSTEM (object); ShellAppSystemPrivate *priv = self->priv; - gmenu_tree_remove_monitor (priv->tree, on_tree_changed, self); + gmenu_tree_remove_monitor (priv->apps_tree, on_tree_changed, self); + gmenu_tree_remove_monitor (priv->settings_tree, on_tree_changed, self); - gmenu_tree_unref (priv->tree); + gmenu_tree_unref (priv->apps_tree); + gmenu_tree_unref (priv->settings_tree); + + g_slist_foreach (priv->cached_app_menus, (GFunc)shell_app_menu_entry_free, NULL); + g_slist_free (priv->cached_app_menus); + priv->cached_app_menus = NULL; + + g_slist_foreach (priv->cached_setting_ids, (GFunc)g_free, NULL); + g_slist_free (priv->cached_setting_ids); + priv->cached_setting_ids = NULL; G_OBJECT_CLASS (shell_app_system_parent_class)->finalize(object); } static void -reread_menus (ShellAppSystem *self) +reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree) { - GSList *entries = gmenu_tree_directory_get_contents (self->priv->trunk); - GSList *iter; ShellAppSystemPrivate *priv = self->priv; + GMenuTreeDirectory *trunk; + GSList *entries; + GSList *iter; - g_list_foreach (self->priv->cached_menus, (GFunc)shell_app_menu_entry_free, NULL); - g_list_free (self->priv->cached_menus); - self->priv->cached_menus = NULL; + trunk = gmenu_tree_get_root_directory (tree); + entries = gmenu_tree_directory_get_contents (trunk); + + g_slist_foreach (*cache, (GFunc)shell_app_menu_entry_free, NULL); + g_slist_free (*cache); + *cache = NULL; for (iter = entries; iter; iter = iter->next) { @@ -124,12 +140,11 @@ reread_menus (ShellAppSystem *self) { GMenuTreeDirectory *dir = iter->data; ShellAppMenuEntry *shell_entry = g_new0 (ShellAppMenuEntry, 1); - shell_entry->name = g_strdup (gmenu_tree_directory_get_name (dir)); shell_entry->id = g_strdup (gmenu_tree_directory_get_menu_id (dir)); shell_entry->icon = g_strdup (gmenu_tree_directory_get_icon (dir)); - priv->cached_menus = g_list_prepend (priv->cached_menus, shell_entry); + *cache = g_slist_prepend (*cache, shell_entry); gmenu_tree_item_unref (dir); } @@ -138,9 +153,74 @@ reread_menus (ShellAppSystem *self) break; } } - priv->cached_menus = g_list_reverse (priv->cached_menus); + *cache = g_slist_reverse (*cache); g_slist_free (entries); + gmenu_tree_item_unref (trunk); +} + +static GSList * +gather_entries_recurse (ShellAppSystem *monitor, + GSList *ids, + GMenuTreeDirectory *root) +{ + GSList *contents; + GSList *iter; + + contents = gmenu_tree_directory_get_contents (root); + + for (iter = contents; iter; iter = iter->next) + { + GMenuTreeItem *item = iter->data; + switch (gmenu_tree_item_get_type (item)) + { + case GMENU_TREE_ITEM_ENTRY: + { + GMenuTreeEntry *entry = (GMenuTreeEntry *)item; + const char *id = gmenu_tree_entry_get_desktop_file_id (entry); + ids = g_slist_prepend (ids, g_strdup (id)); + } + break; + case GMENU_TREE_ITEM_DIRECTORY: + { + GMenuTreeDirectory *dir = (GMenuTreeDirectory*)item; + ids = gather_entries_recurse (monitor, ids, dir); + } + break; + default: + break; + } + gmenu_tree_item_unref (item); + } + + g_slist_free (contents); + + return ids; +} + +static void +reread_entries (ShellAppSystem *self, + GSList **cache, + GMenuTree *tree) +{ + GMenuTreeDirectory *trunk; + + trunk = gmenu_tree_get_root_directory (tree); + + g_slist_foreach (*cache, (GFunc)g_free, NULL); + g_slist_free (*cache); + *cache = NULL; + + *cache = gather_entries_recurse (self, *cache, trunk); + + gmenu_tree_item_unref (trunk); +} + +static void +reread_menus (ShellAppSystem *self) +{ + reread_directories (self, &(self->priv->cached_app_menus), self->priv->apps_tree); + reread_entries (self, &(self->priv->cached_setting_ids), self->priv->settings_tree); } static void @@ -166,51 +246,15 @@ shell_app_menu_entry_get_type (void) return gtype; } -static GList * -gather_entries_recurse (ShellAppSystem *monitor, - GList *ids, - GMenuTreeDirectory *root) -{ - GSList *contents; - GSList *iter; - - contents = gmenu_tree_directory_get_contents (root); - - for (iter = contents; iter; iter = iter->next) - { - GMenuTreeItem *item = iter->data; - switch (gmenu_tree_item_get_type (item)) - { - case GMENU_TREE_ITEM_ENTRY: - { - GMenuTreeEntry *entry = (GMenuTreeEntry *)item; - const char *id = gmenu_tree_entry_get_desktop_file_id (entry); - ids = g_list_prepend (ids, g_strdup (id)); - } - break; - case GMENU_TREE_ITEM_DIRECTORY: - { - GMenuTreeDirectory *dir = (GMenuTreeDirectory*)item; - ids = gather_entries_recurse (monitor, ids, dir); - } - break; - default: - break; - } - gmenu_tree_item_unref (item); - } - - g_slist_free (contents); - - return ids; -} - /** * shell_app_system_get_applications_for_menu: * + * Traverses a toplevel menu, and returns all items under it. Nested items + * are flattened. + * * Return value: (transfer full) (element-type utf8): List of desktop file ids */ -GList * +GSList * shell_app_system_get_applications_for_menu (ShellAppSystem *monitor, const char *menu) { @@ -218,7 +262,7 @@ shell_app_system_get_applications_for_menu (ShellAppSystem *monitor, GMenuTreeDirectory *menu_entry; path = g_strdup_printf ("/%s", menu); - menu_entry = gmenu_tree_get_directory_from_path (monitor->priv->tree, path); + menu_entry = gmenu_tree_get_directory_from_path (monitor->priv->apps_tree, path); g_free (path); g_assert (menu_entry != NULL); @@ -228,10 +272,25 @@ shell_app_system_get_applications_for_menu (ShellAppSystem *monitor, /** * shell_app_system_get_menus: * + * Returns a list of toplevel menu names, like "Accessories", "Programming", etc. + * * Return value: (transfer none) (element-type AppMenuEntry): List of toplevel menus */ -GList * +GSList * shell_app_system_get_menus (ShellAppSystem *monitor) { - return monitor->priv->cached_menus; + return monitor->priv->cached_app_menus; +} + +/** + * shell_app_system_get_all_settings: + * + * Returns a list of all desktop file ids under "settings.menu". + * + * Return value: (transfer full) (element-type utf8): List of desktop file ids + */ +GSList * +shell_app_system_get_all_settings (ShellAppSystem *monitor) +{ + return monitor->priv->cached_setting_ids; } diff --git a/src/shell-app-system.h b/src/shell-app-system.h index 090643fb3..cbd2d2e37 100644 --- a/src/shell-app-system.h +++ b/src/shell-app-system.h @@ -31,7 +31,7 @@ struct _ShellAppSystemClass GType shell_app_system_get_type (void) G_GNUC_CONST; ShellAppSystem* shell_app_system_new(void); -GList *shell_app_system_get_applications_for_menu (ShellAppSystem *monitor, const char *menu); +GSList *shell_app_system_get_applications_for_menu (ShellAppSystem *system, const char *menu); typedef struct _ShellAppMenuEntry ShellAppMenuEntry; @@ -43,6 +43,8 @@ struct _ShellAppMenuEntry { GType shell_app_menu_entry_get_type (void); -GList *shell_app_system_get_menus (ShellAppSystem *monitor); +GSList *shell_app_system_get_menus (ShellAppSystem *system); + +GSList *shell_app_system_get_all_settings (ShellAppSystem *system); #endif /* __SHELL_APP_SYSTEM_H__ */