--- src/update-desktop-database.c +++ src/update-desktop-database.c @@ -42,11 +42,91 @@ #define udd_print(...) if (!quiet) g_printerr (__VA_ARGS__) #define udd_verbose_print(...) if (verbose) g_printerr (__VA_ARGS__) +enum defaults_order { + DEFAULT_FOR_MIME, + PREFERRED_DEFAULT, + PLAIN_DEFAULT, + CATEGORIES_MATCH, + UNKNOWN +}; + +struct mime_default { + gchar *desktop_file; + enum defaults_order order; + gint suborder; +}; + +struct desktop_environment { + gchar *prefix; /* XDG prefix */ + GHashTable *defaults_for_mime; /* key: mime-type, value: desktop file */ + GList *preferred_default_desktops; /* data: desktop file */ + GList *default_desktops; /* data: desktop file */ + GList *categories; /* data: categories */ + GList *inherit; /* data: struct desktop_environment */ + GList *inherit_names; /* data: gchar* */ + GHashTable *recognized_defaults; /* key: mime/type, value: mime_default */ + enum defaults_order processing_order; /* relevant to desktop file just processed */ + gint processing_suborder; /* relevant to desktop file just processed */ +}; + +/** + * g_list_index_custom: + * @list: a #GList + * @data: user data passed to the function + * @func: the function to call for each element. + * It should return 0 when the desired element is found + * + * Gets the position of the element containing + * the given data (starting from 0), using a supplied function to + * find the desired element. It iterates over the list, calling + * the given function which should return 0 when the desired + * element is found. The function takes two #gconstpointer arguments, + * the #GList element's data as the first argument and the + * given user data. + * + * Returns: the index of the element containing the data, + * or -1 if the data is not found + */ +static gint +g_list_index_custom (GList *list, + gconstpointer data, + GCompareFunc func) +{ + gint i; + + i = 0; + while (list) + { + if (! func (list->data, data)) + return i; + i++; + list = list->next; + } + + return -1; +} + +static inline gint +g_string_compare_equal (gconstpointer a, + gconstpointer b) +{ + if (g_strcmp0 (a, b)) + return 1; + else + return 0; +} + static FILE *open_temp_cache_file (const char *dir, char **filename, GError **error); static void add_mime_type (const char *mime_type, GList *desktop_files, FILE *f); static void sync_database (const char *dir, GError **error); +static void +register_default_for_mime (GHashTable *recognized_defaults, + const char *mime_type, + const char *desktop_file, + enum defaults_order order, + gint suborder); static void cache_desktop_file (const char *desktop_file, const char *mime_type, GError **error); @@ -63,6 +143,7 @@ static void print_desktop_dirs (const char **dirs); static GHashTable *mime_types_map = NULL; +static GList *enviro_list = NULL; static gboolean verbose = FALSE, quiet = FALSE; static void @@ -73,18 +154,80 @@ } static void +register_default_for_mime (GHashTable *recognized_defaults, + const char *mime_type, + const char *desktop_file, + enum defaults_order order, + gint suborder) +{ + struct mime_default *current_default; + + current_default = g_hash_table_lookup (recognized_defaults, mime_type); + + if (current_default) + { + if (order < current_default->order || + (order == current_default->order && suborder < current_default->suborder)) + { + g_free (current_default->desktop_file); + current_default->desktop_file = g_strdup (desktop_file); + current_default->order = order; + current_default->suborder = suborder; + printf ("changing default: %p, %s by %s\n", recognized_defaults, mime_type, desktop_file); + } + } + else + { + current_default = g_new (struct mime_default, 1); + current_default->desktop_file = g_strdup (desktop_file); + current_default->order = order; + current_default->suborder = suborder; + printf ("registering default: %p, %s by %s\n", recognized_defaults, mime_type, desktop_file); + g_hash_table_insert (recognized_defaults, g_strdup (mime_type), current_default); + } +} + + +static void cache_desktop_file (const char *desktop_file, const char *mime_type, GError **error) { - GList *desktop_files; + GList *desktop_files, *list; desktop_files = (GList *) g_hash_table_lookup (mime_types_map, mime_type); desktop_files = g_list_prepend (desktop_files, g_strdup (desktop_file)); g_hash_table_insert (mime_types_map, g_strdup (mime_type), desktop_files); -} + printf ("caching %s for %s\n", desktop_file, mime_type); + list = enviro_list; + while (list) + { + printf (" for %p\n", list); + struct desktop_environment *enviro = list->data; + const gchar *current_default; + + /* desktop listed as default for certain MIME type */ + current_default = g_hash_table_lookup (enviro->defaults_for_mime, mime_type); + if (!g_strcmp0 (desktop_file, current_default)) + { + printf ("processing %s: DEFAULT_FOR_MIME, 0\n", desktop_file); + register_default_for_mime (enviro->recognized_defaults, mime_type, desktop_file, + DEFAULT_FOR_MIME, 0); + } + /* desktop listed in other way */ + else if (enviro->processing_order != UNKNOWN) + { + register_default_for_mime (enviro->recognized_defaults, mime_type, desktop_file, + enviro->processing_order, enviro->processing_suborder); + printf ("processing %s: %d, %d\n", desktop_file, enviro->processing_order, enviro->processing_suborder); + } + else printf ("processing unknown %s\n", desktop_file); + + list = g_list_next (list); + } +} static gboolean is_valid_mime_type_char (const guchar c) @@ -175,9 +318,11 @@ { GError *load_error; GKeyFile *keyfile; - char **mime_types; + GList *list; + char **mime_types, **categories; int i; + load_error = NULL; keyfile = g_key_file_new (); load_error = NULL; @@ -193,6 +338,9 @@ mime_types = g_key_file_get_string_list (keyfile, GROUP_DESKTOP_ENTRY, "MimeType", NULL, &load_error); + categories = g_key_file_get_string_list (keyfile, + GROUP_DESKTOP_ENTRY, + "Categories", NULL, NULL); g_key_file_free (keyfile); @@ -202,6 +350,51 @@ return; } + list = enviro_list; + while (list) + { + struct desktop_environment *enviro = list->data; + gint suborder; + + printf ("%s: processing for %p\n", name, enviro); + + enviro->processing_order = UNKNOWN; + suborder = g_list_index_custom (enviro->preferred_default_desktops, name, g_string_compare_equal); + if (suborder != -1) + { + enviro->processing_order = PREFERRED_DEFAULT; + enviro->processing_suborder = suborder; + printf ("%s considered as PREFERRED_DEFAULT for %p\n", name, enviro); + } + else + { + suborder = g_list_index_custom (enviro->default_desktops, name, g_string_compare_equal); + if (suborder != -1) + { + enviro->processing_order = PLAIN_DEFAULT; + enviro->processing_suborder = suborder; + printf ("%s considered as PLAIN_DEFAULT for %p\n", name, enviro); + } + else if (categories) + { + gint i, min_suborder = G_MAXINT; + for (i = 0; categories[i] != NULL; i++) + { + suborder = g_list_index_custom (enviro->categories, categories[i], g_string_compare_equal); + if (suborder != -1 && suborder < min_suborder) + { + printf ("%s considered as CATEGORIES_MATCH for %p\n", name, enviro); + enviro->processing_order = CATEGORIES_MATCH; + enviro->processing_suborder = suborder; + min_suborder = suborder; + } + } + } + } + list = g_list_next (list); + } + g_strfreev (categories); + for (i = 0; mime_types[i] != NULL; i++) { char *mime_type; @@ -404,16 +597,167 @@ } static void +strarray_to_list (gchar **strarray, + GList **list) +{ + gchar **ptr; + if (!list) + return; + if (!strarray) + return; + ptr = strarray; + while (*ptr) + { + /* FIXME: error */ + *list = g_list_append (*list, g_strdup (*ptr)); + printf ("strarray to list: %s\n", *ptr); + ptr++; + } +} + +static void +parse_defaults_conf ( + GError **error) +{ + GError *parse_error; + GKeyFile *keyfile; + gchar **groups, **group, **keys, **key; + gchar **strarray, *value; + struct desktop_environment *enviro; + + parse_error = NULL; + keyfile = g_key_file_new (); + g_key_file_load_from_file (keyfile, "desktop-defaults.conf", + G_KEY_FILE_NONE, &parse_error); + + groups = g_key_file_get_groups (keyfile, NULL); + + if (groups) + { + group = groups; + while (*group) + { + keys = g_key_file_get_keys (keyfile, *group, NULL, NULL); + if (keys) + { + printf ("new enviro: %s\n", *group); + enviro = g_new0 (struct desktop_environment, 1); + enviro->defaults_for_mime = g_hash_table_new (g_str_hash, g_str_equal); + enviro->recognized_defaults = g_hash_table_new (g_str_hash, g_str_equal); + enviro_list = g_list_append (enviro_list, enviro); + + if (!strcmp (*group, "Desktop Defaults")) + enviro->prefix = ""; + else + { + value = g_key_file_get_string (keyfile, + *group, + "XDG_DESKTOP_PREFIX", NULL); + if (value) + enviro->prefix = value; + else + { + enviro->prefix = g_strdup_printf ("%s-", *group); + g_free (value); + } + } + + strarray = g_key_file_get_string_list (keyfile, + *group, + "Preferred", NULL, NULL); + strarray_to_list (strarray, &(enviro->preferred_default_desktops)); + + strarray = g_key_file_get_string_list (keyfile, + *group, + "Default", NULL, NULL); + strarray_to_list (strarray, &(enviro->default_desktops)); + + strarray = g_key_file_get_string_list (keyfile, + *group, + "Categories", NULL, NULL); + strarray_to_list (strarray, &(enviro->categories)); + + key = keys; + while (*key) + { + if (strstr (*key, "/")) + { + gchar *desktop_file; + desktop_file = g_key_file_get_string (keyfile, *group, *key, NULL); + if (desktop_file) + g_hash_table_insert (enviro->defaults_for_mime, g_strdup (*key), g_strdup (desktop_file)); + printf ("config default for mime in %p: %s by %s\n", enviro, *key, desktop_file); + } + key++; + } + g_strfreev (keys); + } + group++; + } + g_strfreev (groups); + } + g_key_file_free (keyfile); +} + +static void +generate_default (gpointer key, + gpointer value, + gpointer user_data) +{ + struct mime_default *recognized_default = value; + g_key_file_set_string (user_data, + "Default Applications", + key, + recognized_default->desktop_file); + printf ("recognized: %s, %s\n", (gchar*)key, recognized_default->desktop_file); +} + +static void +generate_defaults_list ( + GError **error) +{ + GList *list; + GKeyFile *keyfile; + GError *generate_error; + + generate_error = NULL; + list = enviro_list; + while (list) + { + gchar *filename; + + keyfile = g_key_file_new (); + + g_key_file_set_comment (keyfile, NULL, NULL, + "This file is auto-generated by update-desktop-database.", + &generate_error); + + struct desktop_environment *enviro = list->data; + g_hash_table_foreach (enviro->recognized_defaults, generate_default, keyfile); + list = g_list_next (list); + + filename = g_strdup_printf ("file:///home/sbrabec/OSC/home:sbrabec:Factory/desktop-file-utils/BUILD/desktop-file-utils-0.15/src/%sdefaults.list", enviro->prefix); + dfu_key_file_to_file (keyfile, filename, &generate_error); + g_free (filename); + g_key_file_free (keyfile); + } + if (generate_error != NULL) + g_propagate_error (error, generate_error); +} + +static void update_database (const char *desktop_dir, GError **error) { GError *update_error; + update_error = NULL; mime_types_map = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); update_error = NULL; + parse_defaults_conf (&update_error); process_desktop_files (desktop_dir, "", &update_error); if (update_error != NULL) @@ -423,6 +767,9 @@ sync_database (desktop_dir, &update_error); if (update_error != NULL) g_propagate_error (error, update_error); + generate_defaults_list (&update_error); + //FIXME: propagate, NULL on run + } g_hash_table_foreach (mime_types_map, (GHFunc) list_free_deep, NULL); g_hash_table_destroy (mime_types_map);