From 951b90f2241758a1c4cbea3992cf5446aecf570d Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Sat, 27 Jul 2013 16:07:40 -0400 Subject: [PATCH] Add support for the desktop file index Add an implementation of GDesktopAppInfo based on the desktop file index. We currently construct keyfile-based GDesktopAppInfos in the least-efficient way imaginable (which still ends up being faster than reading them off the disk). Will be fixed in the future... --- gio/gdesktopappinfo.c | 166 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 3 deletions(-) diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index 6a4050d0b..63ba0fd83 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -49,6 +49,7 @@ #include "gappinfo.h" #include "glocaldirectorymonitor.h" +#include "dfi-reader.h" /** * SECTION:gdesktopappinfo @@ -87,6 +88,12 @@ static void mime_info_cache_reload (const char *dir); static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info, GError **error); +static GDesktopAppInfo * +g_desktop_app_info_new_from_index (const struct dfi_index *dfi, + const struct dfi_pointer_array *array, + guint app_num, + const gchar *desktop_id); + /** * GDesktopAppInfo: * @@ -149,6 +156,7 @@ typedef struct GLocalDirectoryMonitor *monitor; GHashTable *app_names; gboolean is_setup; + struct dfi_index *dfi; } DesktopFileDir; static DesktopFileDir *desktop_file_dirs; @@ -489,6 +497,80 @@ desktop_file_dir_unindexed_get_all (DesktopFileDir *dir, } } +/* Support for indexed DesktopFileDirs {{{2 */ + +#if 0 +enum +{ + DFI_ID_THIS_LOCALE, + + DFI_ID_Desktop_Entry, + + DFI_ID_Name, + DFI_ID_Keywords, + DFI_ID_GenericName, + DFI_ID_X_GNOME_FullName, + DFI_ID_Comment, + + N_DFI_IDS +}; +#endif + +static void +desktop_file_dir_indexed_init (DesktopFileDir *dir) +{ + const struct dfi_string_list *app_names; + guint n_app_names, i; + + dir->app_names = g_hash_table_new (g_str_hash, g_str_equal); + app_names = dfi_index_get_app_names (dir->dfi); + n_app_names = dfi_string_list_get_length (app_names); + + for (i = 0; i < n_app_names; i++) + g_hash_table_insert (dir->app_names, + (gchar *) dfi_string_list_get_string_at_index (app_names, dir->dfi, i), + GUINT_TO_POINTER (i)); +} + +static GDesktopAppInfo * +desktop_file_dir_indexed_get_app (DesktopFileDir *dir, + const gchar *desktop_id) +{ + gpointer value; + guint app_num; + + if (!g_hash_table_lookup_extended (dir->app_names, desktop_id, NULL, &value)) + return NULL; + + app_num = GPOINTER_TO_UINT (value); + + return g_desktop_app_info_new_from_index (dir->dfi, dfi_index_get_desktop_files (dir->dfi), app_num, desktop_id); +} + +static void +desktop_file_dir_indexed_get_all (DesktopFileDir *dir, + GHashTable *apps) +{ + const struct dfi_pointer_array *desktop_files; + guint i, n_desktop_files; + + desktop_files = dfi_index_get_desktop_files (dir->dfi); + + n_desktop_files = dfi_pointer_array_get_length (desktop_files, dir->dfi); + for (i = 0; i < n_desktop_files; i++) + { + const gchar *app_name; + + app_name = dfi_pointer_array_get_item_key (desktop_files, dir->dfi, i); + + if (desktop_file_dir_app_name_is_masked (dir, app_name)) + continue; + + add_to_table_if_appropriate (apps, app_name, + g_desktop_app_info_new_from_index (dir->dfi, desktop_files, i, app_name)); + } +} + /* DesktopFileDir "API" {{{2 */ /*< internal > @@ -532,6 +614,12 @@ desktop_file_dir_reset (DesktopFileDir *dir) dir->app_names = NULL; } + if (dir->dfi) + { + dfi_index_free (dir->dfi); + dir->dfi = NULL; + } + dir->is_setup = FALSE; } @@ -557,7 +645,12 @@ desktop_file_dir_init (DesktopFileDir *dir) g_local_directory_monitor_start (dir->monitor); } - desktop_file_dir_unindexed_init (dir); + dir->dfi = dfi_index_new (dir->path); + + if (dir->dfi) + desktop_file_dir_indexed_init (dir); + else + desktop_file_dir_unindexed_init (dir); dir->is_setup = TRUE; } @@ -580,7 +673,10 @@ desktop_file_dir_get_app (DesktopFileDir *dir, if (!dir->app_names) return NULL; - return desktop_file_dir_unindexed_get_app (dir, desktop_id); + if (dir->dfi) + return desktop_file_dir_indexed_get_app (dir, desktop_id); + else + return desktop_file_dir_unindexed_get_app (dir, desktop_id); } /*< internal > @@ -596,7 +692,10 @@ static void desktop_file_dir_get_all (DesktopFileDir *dir, GHashTable *apps) { - desktop_file_dir_unindexed_get_all (dir, apps); + if (dir->dfi) + desktop_file_dir_indexed_get_all (dir, apps); + else + desktop_file_dir_unindexed_get_all (dir, apps); } /* Lock/unlock and global setup API {{{2 */ @@ -1103,6 +1202,67 @@ g_desktop_app_info_dup (GAppInfo *appinfo) return G_APP_INFO (new_info); } + +static GDesktopAppInfo * +g_desktop_app_info_new_from_index (const struct dfi_index *dfi, + const struct dfi_pointer_array *array, + guint app_num, + const gchar *desktop_id) +{ + const struct dfi_keyfile *keyfile; + GDesktopAppInfo *appinfo; + guint n_groups, i; + GString *string; + GKeyFile *kf; + + keyfile = dfi_keyfile_from_pointer (dfi, dfi_pointer_array_get_pointer (array, app_num)); + + /* What is the least efficient possible way of doing this? Let's see... */ + string = g_string_new (NULL); + + n_groups = dfi_keyfile_get_n_groups (keyfile); + for (i = 0; i < n_groups; i++) + { + const gchar *group_name; + guint start, end; + guint j; + + group_name = dfi_keyfile_get_group_name (keyfile, dfi, i); + g_string_append_printf (string, "[%s]\n", group_name); + + dfi_keyfile_get_group_range (keyfile, i, &start, &end); + + for (j = start; j < end; j++) + { + const gchar *key, *locale, *value; + + dfi_keyfile_get_item (keyfile, dfi, j, &key, &locale, &value); + + if (locale[0]) + g_string_append_printf (string, "%s[%s]=%s\n", key, locale, value); + else + g_string_append_printf (string, "%s=%s\n", key, value); + } + } + + kf = g_key_file_new (); + g_key_file_load_from_data (kf, string->str, string->len, G_KEY_FILE_NONE, NULL); + g_string_free (string, TRUE); + + appinfo = g_object_new (G_TYPE_DESKTOP_APP_INFO, "filename", desktop_id, NULL); + + if (!g_desktop_app_info_load_from_keyfile (appinfo, kf)) + { + g_object_unref (appinfo); + g_key_file_free (kf); + return NULL; + } + + g_key_file_free (kf); + + return appinfo; +} + /* GAppInfo interface implementation functions {{{2 */ static gboolean