summaryrefslogtreecommitdiff
path: root/src/lib/efreet_desktop.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/efreet_desktop.c')
-rw-r--r--src/lib/efreet_desktop.c1085
1 files changed, 1085 insertions, 0 deletions
diff --git a/src/lib/efreet_desktop.c b/src/lib/efreet_desktop.c
new file mode 100644
index 0000000..9293f94
--- /dev/null
+++ b/src/lib/efreet_desktop.c
@@ -0,0 +1,1085 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#undef alloca
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <Ecore_File.h>
+
+/* define macros and variable for using the eina logging system */
+#define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom
+int _efreet_desktop_log_dom = -1;
+
+#include "Efreet.h"
+#include "efreet_private.h"
+
+#define DESKTOP_VERSION "1.0"
+
+/**
+ * The current desktop environment (e.g. "Enlightenment" or "Gnome")
+ */
+static const char *desktop_environment = NULL;
+
+/**
+ * A list of the desktop types available
+ */
+static Eina_List *efreet_desktop_types = NULL;
+
+static Eina_Hash *change_monitors = NULL;
+
+EAPI int EFREET_DESKTOP_TYPE_APPLICATION = 0;
+EAPI int EFREET_DESKTOP_TYPE_LINK = 0;
+EAPI int EFREET_DESKTOP_TYPE_DIRECTORY = 0;
+
+/**
+ * @internal
+ * Information about custom types
+ */
+typedef struct Efreet_Desktop_Type_Info Efreet_Desktop_Type_Info;
+struct Efreet_Desktop_Type_Info
+{
+ int id;
+ const char *type;
+ Efreet_Desktop_Type_Parse_Cb parse_func;
+ Efreet_Desktop_Type_Save_Cb save_func;
+ Efreet_Desktop_Type_Free_Cb free_func;
+};
+
+static int efreet_desktop_read(Efreet_Desktop *desktop);
+static Efreet_Desktop_Type_Info *efreet_desktop_type_parse(const char *type_str);
+static void efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info);
+static void *efreet_desktop_application_fields_parse(Efreet_Desktop *desktop,
+ Efreet_Ini *ini);
+static void efreet_desktop_application_fields_save(Efreet_Desktop *desktop,
+ Efreet_Ini *ini);
+static void *efreet_desktop_link_fields_parse(Efreet_Desktop *desktop,
+ Efreet_Ini *ini);
+static void efreet_desktop_link_fields_save(Efreet_Desktop *desktop,
+ Efreet_Ini *ini);
+static int efreet_desktop_generic_fields_parse(Efreet_Desktop *desktop,
+ Efreet_Ini *ini);
+static void efreet_desktop_generic_fields_save(Efreet_Desktop *desktop,
+ Efreet_Ini *ini);
+static Eina_Bool efreet_desktop_x_fields_parse(const Eina_Hash *hash,
+ const void *key,
+ void *data,
+ void *fdata);
+static Eina_Bool efreet_desktop_x_fields_save(const Eina_Hash *hash,
+ const void *key,
+ void *value,
+ void *fdata);
+static int efreet_desktop_environment_check(Efreet_Desktop *desktop);
+
+static void efreet_desktop_changes_listen(void);
+static void efreet_desktop_changes_listen_recursive(const char *path);
+static void efreet_desktop_changes_monitor_add(const char *path);
+static void efreet_desktop_changes_cb(void *data, Ecore_File_Monitor *em,
+ Ecore_File_Event event, const char *path);
+
+/**
+ * @internal
+ * @return Returns > 0 on success or 0 on failure
+ * @brief Initialize the Desktop parser subsystem
+ */
+int
+efreet_desktop_init(void)
+{
+ _efreet_desktop_log_dom = eina_log_domain_register
+ ("efreet_desktop", EFREET_DEFAULT_LOG_COLOR);
+ if (_efreet_desktop_log_dom < 0)
+ {
+ EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_desktop");
+ return 0;
+ }
+
+#ifdef HAVE_EVIL
+ if (!evil_sockets_init())
+ {
+ ERR("Could not initialize Winsock system");
+ return 0;
+ }
+#endif
+
+ efreet_desktop_types = NULL;
+
+ EFREET_DESKTOP_TYPE_APPLICATION = efreet_desktop_type_add("Application",
+ efreet_desktop_application_fields_parse,
+ efreet_desktop_application_fields_save,
+ NULL);
+ EFREET_DESKTOP_TYPE_LINK = efreet_desktop_type_add("Link",
+ efreet_desktop_link_fields_parse,
+ efreet_desktop_link_fields_save, NULL);
+ EFREET_DESKTOP_TYPE_DIRECTORY = efreet_desktop_type_add("Directory", NULL,
+ NULL, NULL);
+
+ efreet_desktop_changes_listen();
+ return 1;
+}
+
+/**
+ * @internal
+ * @returns the number of initializations left for this system
+ * @brief Attempts to shut down the subsystem if nothing else is using it
+ */
+void
+efreet_desktop_shutdown(void)
+{
+ Efreet_Desktop_Type_Info *info;
+
+ IF_RELEASE(desktop_environment);
+ EINA_LIST_FREE(efreet_desktop_types, info)
+ efreet_desktop_type_info_free(info);
+ IF_FREE_HASH(change_monitors);
+#ifdef HAVE_EVIL
+ evil_sockets_shutdown();
+#endif
+ eina_log_domain_unregister(_efreet_desktop_log_dom);
+ _efreet_desktop_log_dom = -1;
+}
+
+EAPI Efreet_Desktop *
+efreet_desktop_get(const char *file)
+{
+ Efreet_Desktop *desktop;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+ desktop = efreet_desktop_new(file);
+ if (!desktop) return NULL;
+
+ /* If we didn't find this file in the eet cache, add path to search path */
+ if (!desktop->eet)
+ {
+ /* Check whether the desktop type is a system type,
+ * and therefor known by the cache builder */
+ Efreet_Desktop_Type_Info *info;
+
+ info = eina_list_nth(efreet_desktop_types, desktop->type);
+ if (info && (
+ info->id == EFREET_DESKTOP_TYPE_APPLICATION ||
+ info->id == EFREET_DESKTOP_TYPE_LINK ||
+ info->id == EFREET_DESKTOP_TYPE_DIRECTORY
+ ))
+ efreet_cache_desktop_add(desktop);
+ }
+
+ return desktop;
+}
+
+EAPI int
+efreet_desktop_ref(Efreet_Desktop *desktop)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
+ desktop->ref++;
+ return desktop->ref;
+}
+
+EAPI Efreet_Desktop *
+efreet_desktop_empty_new(const char *file)
+{
+ Efreet_Desktop *desktop;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+ desktop = NEW(Efreet_Desktop, 1);
+ if (!desktop) return NULL;
+
+ desktop->orig_path = strdup(file);
+ desktop->load_time = ecore_file_mod_time(file);
+
+ desktop->ref = 1;
+
+ return desktop;
+}
+
+EAPI Efreet_Desktop *
+efreet_desktop_new(const char *file)
+{
+ Efreet_Desktop *desktop = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+ desktop = efreet_cache_desktop_find(file);
+ if (desktop)
+ {
+ desktop->ref++;
+ if (!efreet_desktop_environment_check(desktop))
+ {
+ efreet_desktop_free(desktop);
+ return NULL;
+ }
+ return desktop;
+ efreet_desktop_free(desktop);
+ }
+ return efreet_desktop_uncached_new(file);
+}
+
+EAPI Efreet_Desktop *
+efreet_desktop_uncached_new(const char *file)
+{
+ Efreet_Desktop *desktop = NULL;
+ char rp[PATH_MAX];
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+ if (!realpath(file, rp)) return NULL;
+ if (!ecore_file_exists(rp)) return NULL;
+
+ desktop = NEW(Efreet_Desktop, 1);
+ if (!desktop) return NULL;
+ desktop->orig_path = strdup(rp);
+ desktop->ref = 1;
+ if (!efreet_desktop_read(desktop))
+ {
+ efreet_desktop_free(desktop);
+ return NULL;
+ }
+
+ return desktop;
+}
+
+EAPI int
+efreet_desktop_save(Efreet_Desktop *desktop)
+{
+ Efreet_Desktop_Type_Info *info;
+ Efreet_Ini *ini;
+ int ok = 1;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
+
+ ini = efreet_ini_new(NULL);
+ if (!ini) return 0;
+ efreet_ini_section_add(ini, "Desktop Entry");
+ efreet_ini_section_set(ini, "Desktop Entry");
+
+ info = eina_list_nth(efreet_desktop_types, desktop->type);
+ if (info)
+ {
+ efreet_ini_string_set(ini, "Type", info->type);
+ if (info->save_func) info->save_func(desktop, ini);
+ }
+ else
+ ok = 0;
+
+ if (ok)
+ {
+ char *val;
+
+ if (desktop->only_show_in)
+ {
+ val = efreet_desktop_string_list_join(desktop->only_show_in);
+ if (val)
+ {
+ efreet_ini_string_set(ini, "OnlyShowIn", val);
+ FREE(val);
+ }
+ }
+ if (desktop->not_show_in)
+ {
+ val = efreet_desktop_string_list_join(desktop->not_show_in);
+ if (val)
+ {
+ efreet_ini_string_set(ini, "NotShowIn", val);
+ FREE(val);
+ }
+ }
+ efreet_desktop_generic_fields_save(desktop, ini);
+ /* When we save the file, it should be updated to the
+ * latest version that we support! */
+ efreet_ini_string_set(ini, "Version", DESKTOP_VERSION);
+
+ if (!efreet_ini_save(ini, desktop->orig_path)) ok = 0;
+ }
+ efreet_ini_free(ini);
+ return ok;
+}
+
+EAPI int
+efreet_desktop_save_as(Efreet_Desktop *desktop, const char *file)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
+
+ /* If we save data from eet as new, we will be in trouble */
+ if (desktop->eet) return 0;
+
+ IF_FREE(desktop->orig_path);
+ desktop->orig_path = strdup(file);
+ return efreet_desktop_save(desktop);
+}
+
+EAPI void
+efreet_desktop_free(Efreet_Desktop *desktop)
+{
+ if (!desktop) return;
+
+ desktop->ref--;
+ if (desktop->ref > 0) return;
+
+ if (desktop->eet)
+ {
+ efreet_cache_desktop_free(desktop);
+ }
+ else
+ {
+ IF_FREE(desktop->orig_path);
+
+ IF_FREE(desktop->version);
+ IF_FREE(desktop->name);
+ IF_FREE(desktop->generic_name);
+ IF_FREE(desktop->comment);
+ IF_FREE(desktop->icon);
+ IF_FREE(desktop->url);
+
+ IF_FREE(desktop->try_exec);
+ IF_FREE(desktop->exec);
+ IF_FREE(desktop->path);
+ IF_FREE(desktop->startup_wm_class);
+
+ IF_FREE_LIST(desktop->only_show_in, eina_stringshare_del);
+ IF_FREE_LIST(desktop->not_show_in, eina_stringshare_del);
+
+ IF_FREE_LIST(desktop->categories, eina_stringshare_del);
+ IF_FREE_LIST(desktop->mime_types, eina_stringshare_del);
+
+ IF_FREE_HASH(desktop->x);
+
+ if (desktop->type_data)
+ {
+ Efreet_Desktop_Type_Info *info;
+ info = eina_list_nth(efreet_desktop_types, desktop->type);
+ if (info->free_func)
+ info->free_func(desktop->type_data);
+ }
+ free(desktop);
+ }
+}
+
+EAPI void
+efreet_desktop_environment_set(const char *environment)
+{
+ if (desktop_environment) eina_stringshare_del(desktop_environment);
+ if (environment) desktop_environment = eina_stringshare_add(environment);
+ else desktop_environment = NULL;
+}
+
+EAPI const char *
+efreet_desktop_environment_get(void)
+{
+ return desktop_environment;
+}
+
+EAPI unsigned int
+efreet_desktop_category_count_get(Efreet_Desktop *desktop)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
+ return eina_list_count(desktop->categories);
+}
+
+EAPI void
+efreet_desktop_category_add(Efreet_Desktop *desktop, const char *category)
+{
+ EINA_SAFETY_ON_NULL_RETURN(desktop);
+ EINA_SAFETY_ON_NULL_RETURN(category);
+
+ if (eina_list_search_unsorted(desktop->categories,
+ EINA_COMPARE_CB(strcmp), category)) return;
+
+ desktop->categories = eina_list_append(desktop->categories,
+ (void *)eina_stringshare_add(category));
+}
+
+EAPI int
+efreet_desktop_category_del(Efreet_Desktop *desktop, const char *category)
+{
+ char *found = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
+
+ if ((found = eina_list_search_unsorted(desktop->categories,
+ EINA_COMPARE_CB(strcmp), category)))
+ {
+ eina_stringshare_del(found);
+ desktop->categories = eina_list_remove(desktop->categories, found);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+EAPI int
+efreet_desktop_type_add(const char *type, Efreet_Desktop_Type_Parse_Cb parse_func,
+ Efreet_Desktop_Type_Save_Cb save_func,
+ Efreet_Desktop_Type_Free_Cb free_func)
+{
+ int id;
+ Efreet_Desktop_Type_Info *info;
+
+ info = NEW(Efreet_Desktop_Type_Info, 1);
+ if (!info) return 0;
+
+ id = eina_list_count(efreet_desktop_types);
+
+ info->id = id;
+ info->type = eina_stringshare_add(type);
+ info->parse_func = parse_func;
+ info->save_func = save_func;
+ info->free_func = free_func;
+
+ efreet_desktop_types = eina_list_append(efreet_desktop_types, info);
+
+ return id;
+}
+
+EAPI int
+efreet_desktop_type_alias(int from_type, const char *alias)
+{
+ Efreet_Desktop_Type_Info *info;
+ info = eina_list_nth(efreet_desktop_types, from_type);
+ if (!info) return -1;
+
+ return efreet_desktop_type_add(alias, info->parse_func, info->save_func, info->free_func);
+}
+
+EAPI Eina_Bool
+efreet_desktop_x_field_set(Efreet_Desktop *desktop, const char *key, const char *data)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), EINA_FALSE);
+
+ if (!desktop->x)
+ desktop->x = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
+
+ eina_hash_del_by_key(desktop->x, key);
+ eina_hash_add(desktop->x, key, eina_stringshare_add(data));
+
+ return EINA_TRUE;
+}
+
+EAPI const char *
+efreet_desktop_x_field_get(Efreet_Desktop *desktop, const char *key)
+{
+ const char *ret;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->x, NULL);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), NULL);
+
+ ret = eina_hash_find(desktop->x, key);
+ if (!ret)
+ return NULL;
+
+ return eina_stringshare_add(ret);
+}
+
+EAPI Eina_Bool
+efreet_desktop_x_field_del(Efreet_Desktop *desktop, const char *key)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->x, EINA_FALSE);
+
+ return eina_hash_del_by_key(desktop->x, key);
+}
+
+EAPI void *
+efreet_desktop_type_data_get(Efreet_Desktop *desktop)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL);
+ return desktop->type_data;
+}
+
+EAPI Eina_List *
+efreet_desktop_string_list_parse(const char *string)
+{
+ Eina_List *list = NULL;
+ char *tmp;
+ char *s, *p;
+ size_t len;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(string, NULL);
+
+ len = strlen(string) + 1;
+ tmp = alloca(len);
+ memcpy(tmp, string, len);
+ s = tmp;
+
+ while ((p = strchr(s, ';')))
+ {
+ if (p > tmp && *(p-1) == '\\') continue;
+ *p = '\0';
+ list = eina_list_append(list, (void *)eina_stringshare_add(s));
+ s = p + 1;
+ }
+ /* If this is true, the .desktop file does not follow the standard */
+ if (*s)
+ {
+#ifdef STRICT_SPEC
+ WRN("[Efreet]: Found a string list without ';' "
+ "at the end: %s", string);
+#endif
+ list = eina_list_append(list, (void *)eina_stringshare_add(s));
+ }
+
+ return list;
+}
+
+EAPI char *
+efreet_desktop_string_list_join(Eina_List *list)
+{
+ Eina_List *l;
+ const char *elem;
+ char *string;
+ size_t size, pos, len;
+
+ if (!list) return strdup("");
+
+ size = 1024;
+ string = malloc(size);
+ if (!string) return NULL;
+ pos = 0;
+
+ EINA_LIST_FOREACH(list, l, elem)
+ {
+ len = strlen(elem);
+ /* +1 for ';' */
+ if ((len + pos + 1) >= size)
+ {
+ char *tmp;
+ size = len + pos + 1024;
+ tmp = realloc(string, size);
+ if (!tmp)
+ {
+ free(string);
+ return NULL;
+ }
+ string = tmp;
+ }
+ strcpy(string + pos, elem);
+ pos += len;
+ strcpy(string + pos, ";");
+ pos += 1;
+ }
+ return string;
+}
+
+/**
+ * @internal
+ * @param desktop The desktop to fill
+ * @return Returns 1 on success, 0 on failure
+ * @brief initialize an Efreet_Desktop from the contents of @a file
+ */
+static int
+efreet_desktop_read(Efreet_Desktop *desktop)
+{
+ Efreet_Ini *ini;
+ int error = 0;
+ int ok;
+
+ ini = efreet_ini_new(desktop->orig_path);
+ if (!ini) return 0;
+ if (!ini->data)
+ {
+ efreet_ini_free(ini);
+ return 0;
+ }
+
+ ok = efreet_ini_section_set(ini, "Desktop Entry");
+ if (!ok) ok = efreet_ini_section_set(ini, "KDE Desktop Entry");
+ if (!ok)
+ {
+ ERR("efreet_desktop_new error: no Desktop Entry section");
+ error = 1;
+ }
+
+ if (!error)
+ {
+ Efreet_Desktop_Type_Info *info;
+
+ info = efreet_desktop_type_parse(efreet_ini_string_get(ini, "Type"));
+ if (info)
+ {
+ const char *val;
+
+ desktop->type = info->id;
+ val = efreet_ini_string_get(ini, "Version");
+ if (val) desktop->version = strdup(val);
+
+ if (info->parse_func)
+ desktop->type_data = info->parse_func(desktop, ini);
+ }
+ else
+ error = 1;
+ }
+
+ if (!error && !efreet_desktop_generic_fields_parse(desktop, ini)) error = 1;
+ if (!error && !efreet_desktop_environment_check(desktop)) error = 1;
+ if (!error)
+ eina_hash_foreach(ini->section, efreet_desktop_x_fields_parse, desktop);
+
+ efreet_ini_free(ini);
+
+ desktop->load_time = ecore_file_mod_time(desktop->orig_path);
+
+ if (error) return 0;
+
+ return 1;
+}
+
+/**
+ * @internal
+ * @param type_str the type as a string
+ * @return the parsed type
+ * @brief parse the type string into an Efreet_Desktop_Type
+ */
+static Efreet_Desktop_Type_Info *
+efreet_desktop_type_parse(const char *type_str)
+{
+ Efreet_Desktop_Type_Info *info;
+ Eina_List *l;
+
+ if (!type_str) return NULL;
+
+ EINA_LIST_FOREACH(efreet_desktop_types, l, info)
+ {
+ if (!strcmp(info->type, type_str))
+ return info;
+ }
+
+ return NULL;
+}
+
+/**
+ * @internal
+ * @brief Free an Efreet Desktop_Type_Info struct
+ */
+static void
+efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info)
+{
+ if (!info) return;
+ IF_RELEASE(info->type);
+ free(info);
+}
+
+/**
+ * @internal
+ * @param desktop the Efreet_Desktop to store parsed fields in
+ * @param ini the Efreet_Ini to parse fields from
+ * @return No value
+ * @brief Parse application specific desktop fields
+ */
+static void *
+efreet_desktop_application_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini)
+{
+ const char *val;
+
+ val = efreet_ini_string_get(ini, "TryExec");
+ if (val) desktop->try_exec = strdup(val);
+
+ val = efreet_ini_string_get(ini, "Exec");
+ if (val) desktop->exec = strdup(val);
+
+ val = efreet_ini_string_get(ini, "Path");
+ if (val) desktop->path = strdup(val);
+
+ val = efreet_ini_string_get(ini, "StartupWMClass");
+ if (val) desktop->startup_wm_class = strdup(val);
+
+ val = efreet_ini_string_get(ini, "Categories");
+ if (val)
+ desktop->categories = efreet_desktop_string_list_parse(val);
+ val = efreet_ini_string_get(ini, "MimeType");
+ if (val) desktop->mime_types = efreet_desktop_string_list_parse(val);
+
+ desktop->terminal = efreet_ini_boolean_get(ini, "Terminal");
+ desktop->startup_notify = efreet_ini_boolean_get(ini, "StartupNotify");
+
+ return NULL;
+}
+
+/**
+ * @internal
+ * @param desktop the Efreet_Desktop to save fields from
+ * @param ini the Efreet_Ini to save fields to
+ * @return Returns no value
+ * @brief Save application specific desktop fields
+ */
+static void
+efreet_desktop_application_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini)
+{
+ char *val;
+
+ if (desktop->try_exec)
+ efreet_ini_string_set(ini, "TryExec", desktop->try_exec);
+
+ if (desktop->exec)
+ efreet_ini_string_set(ini, "Exec", desktop->exec);
+
+ if (desktop->path)
+ efreet_ini_string_set(ini, "Path", desktop->path);
+
+ if (desktop->startup_wm_class)
+ efreet_ini_string_set(ini, "StartupWMClass", desktop->startup_wm_class);
+
+ if (desktop->categories)
+ {
+ val = efreet_desktop_string_list_join(desktop->categories);
+ if (val)
+ {
+ efreet_ini_string_set(ini, "Categories", val);
+ FREE(val);
+ }
+ }
+
+ if (desktop->mime_types)
+ {
+ val = efreet_desktop_string_list_join(desktop->mime_types);
+ if (val)
+ {
+ efreet_ini_string_set(ini, "MimeType", val);
+ FREE(val);
+ }
+ }
+
+ efreet_ini_boolean_set(ini, "Terminal", desktop->terminal);
+ efreet_ini_boolean_set(ini, "StartupNotify", desktop->startup_notify);
+}
+
+/**
+ * @internal
+ * @param desktop the Efreet_Desktop to store parsed fields in
+ * @param ini the Efreet_Ini to parse fields from
+ * @return Returns no value
+ * @brief Parse link specific desktop fields
+ */
+static void *
+efreet_desktop_link_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini)
+{
+ const char *val;
+
+ val = efreet_ini_string_get(ini, "URL");
+ if (val) desktop->url = strdup(val);
+ return NULL;
+}
+
+/**
+ * @internal
+ * @param desktop the Efreet_Desktop to save fields from
+ * @param ini the Efreet_Ini to save fields in
+ * @return Returns no value
+ * @brief Save link specific desktop fields
+ */
+static void
+efreet_desktop_link_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini)
+{
+ if (desktop->url) efreet_ini_string_set(ini, "URL", desktop->url);
+}
+
+/**
+ * @internal
+ * @param desktop the Efreet_Desktop to store parsed fields in
+ * @param ini the Efreet_Ini to parse fields from
+ * @return 1 if parsed successfully, 0 otherwise
+ * @brief Parse desktop fields that all types can include
+ */
+static int
+efreet_desktop_generic_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini)
+{
+ const char *val;
+ const char *not_show_in = NULL, *only_show_in = NULL;
+
+ val = efreet_ini_localestring_get(ini, "Name");
+#ifndef STRICT_SPEC
+ if (!val) val = efreet_ini_localestring_get(ini, "_Name");
+#endif
+ if (val) desktop->name = strdup(val);
+ else
+ {
+ ERR("efreet_desktop_generic_fields_parse error: no Name or _Name fields");
+ return 0;
+ }
+
+ val = efreet_ini_localestring_get(ini, "GenericName");
+ if (val) desktop->generic_name = strdup(val);
+
+ val = efreet_ini_localestring_get(ini, "Comment");
+#ifndef STRICT_SPEC
+ if (!val) val = efreet_ini_localestring_get(ini, "_Comment");
+#endif
+ if (val) desktop->comment = strdup(val);
+
+ val = efreet_ini_localestring_get(ini, "Icon");
+ if (val) desktop->icon = strdup(val);
+
+ desktop->no_display = efreet_ini_boolean_get(ini, "NoDisplay");
+ desktop->hidden = efreet_ini_boolean_get(ini, "Hidden");
+
+ only_show_in = efreet_ini_string_get(ini, "OnlyShowIn");
+ not_show_in = efreet_ini_string_get(ini, "NotShowIn");
+ if (only_show_in && not_show_in)
+ WRN("Both OnlyShowIn and NotShowIn in %s, preferring OnlyShowIn", desktop->orig_path);
+ if (only_show_in) desktop->only_show_in = efreet_desktop_string_list_parse(only_show_in);
+ else if (not_show_in) desktop->not_show_in = efreet_desktop_string_list_parse(not_show_in);
+
+ return 1;
+}
+
+/**
+ * @internal
+ * @param desktop the Efreet_Desktop to save fields from
+ * @param ini the Efreet_Ini to save fields to
+ * @return Returns nothing
+ * @brief Save desktop fields that all types can include
+ */
+static void
+efreet_desktop_generic_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini)
+{
+ const char *val;
+
+ if (desktop->name)
+ {
+ efreet_ini_localestring_set(ini, "Name", desktop->name);
+ val = efreet_ini_string_get(ini, "Name");
+ if (!val)
+ efreet_ini_string_set(ini, "Name", desktop->name);
+ }
+ if (desktop->generic_name)
+ {
+ efreet_ini_localestring_set(ini, "GenericName", desktop->generic_name);
+ val = efreet_ini_string_get(ini, "GenericName");
+ if (!val)
+ efreet_ini_string_set(ini, "GenericName", desktop->generic_name);
+ }
+ if (desktop->comment)
+ {
+ efreet_ini_localestring_set(ini, "Comment", desktop->comment);
+ val = efreet_ini_string_get(ini, "Comment");
+ if (!val)
+ efreet_ini_string_set(ini, "Comment", desktop->comment);
+ }
+ if (desktop->icon)
+ {
+ efreet_ini_localestring_set(ini, "Icon", desktop->icon);
+ val = efreet_ini_string_get(ini, "Icon");
+ if (!val)
+ efreet_ini_string_set(ini, "Icon", desktop->icon);
+ }
+
+ efreet_ini_boolean_set(ini, "NoDisplay", desktop->no_display);
+ efreet_ini_boolean_set(ini, "Hidden", desktop->hidden);
+
+ if (desktop->x) eina_hash_foreach(desktop->x, efreet_desktop_x_fields_save,
+ ini);
+}
+
+/**
+ * @internal
+ * @param node The node to work with
+ * @param desktop The desktop file to work with
+ * @return Returns always true, to be used in eina_hash_foreach()
+ * @brief Parses out an X- key from @a node and stores in @a desktop
+ */
+static Eina_Bool
+efreet_desktop_x_fields_parse(const Eina_Hash *hash __UNUSED__, const void *key, void *value, void *fdata)
+{
+ Efreet_Desktop * desktop = fdata;
+
+ if (!desktop) return EINA_TRUE;
+ if (strncmp(key, "X-", 2)) return EINA_TRUE;
+
+ if (!desktop->x)
+ desktop->x = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
+ eina_hash_del_by_key(desktop->x, key);
+ eina_hash_add(desktop->x, key, (void *)eina_stringshare_add(value));
+
+ return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @param node The node to work with
+ * @param ini The ini file to work with
+ * @return Returns no value
+ * @brief Stores an X- key from @a node and stores in @a ini
+ */
+static Eina_Bool
+efreet_desktop_x_fields_save(const Eina_Hash *hash __UNUSED__, const void *key, void *value, void *fdata)
+{
+ Efreet_Ini *ini = fdata;
+ efreet_ini_string_set(ini, key, value);
+
+ return EINA_TRUE;
+}
+
+
+/**
+ * @internal
+ * @param ini The Efreet_Ini to parse values from
+ * @return 1 if desktop should be included in current environement, 0 otherwise
+ * @brief Determines if a desktop should be included in the current environment,
+ * based on the values of the OnlyShowIn and NotShowIn fields
+ */
+static int
+efreet_desktop_environment_check(Efreet_Desktop *desktop)
+{
+ Eina_List *list;
+ int found = 0;
+ char *val;
+
+ if (!desktop_environment)
+ {
+ //if (desktop->only_show_in) return 0;
+ return 1;
+ }
+
+ if (desktop->only_show_in)
+ {
+ EINA_LIST_FOREACH(desktop->only_show_in, list, val)
+ {
+ if (!strcmp(val, desktop_environment))
+ {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+ }
+
+
+ if (desktop->not_show_in)
+ {
+ EINA_LIST_FOREACH(desktop->not_show_in, list, val)
+ {
+ if (!strcmp(val, desktop_environment))
+ {
+ found = 1;
+ break;
+ }
+ }
+ return !found;
+ }
+
+ return 1;
+}
+
+static void
+efreet_desktop_changes_listen(void)
+{
+ Efreet_Cache_Array_String *arr;
+ Eina_List *dirs;
+ const char *path;
+
+ if (!efreet_cache_update) return;
+
+ change_monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del));
+ if (!change_monitors) return;
+
+ dirs = efreet_default_dirs_get(efreet_data_home_get(),
+ efreet_data_dirs_get(), "applications");
+
+ EINA_LIST_FREE(dirs, path)
+ {
+ if (ecore_file_is_dir(path))
+ efreet_desktop_changes_listen_recursive(path);
+ eina_stringshare_del(path);
+ }
+
+ arr = efreet_cache_desktop_dirs();
+ if (arr)
+ {
+ unsigned int i;
+
+ for (i = 0; i < arr->array_count; i++)
+ efreet_desktop_changes_monitor_add(arr->array[i]);
+ efreet_cache_array_string_free(arr);
+ }
+}
+
+static void
+efreet_desktop_changes_listen_recursive(const char *path)
+{
+ Eina_Iterator *it;
+ Eina_File_Direct_Info *info;
+
+ efreet_desktop_changes_monitor_add(path);
+
+ it = eina_file_direct_ls(path);
+ if (!it) return;
+ EINA_ITERATOR_FOREACH(it, info)
+ {
+ if (ecore_file_is_dir(info->path)) efreet_desktop_changes_listen_recursive(info->path);
+ }
+ eina_iterator_free(it);
+}
+
+static void
+efreet_desktop_changes_monitor_add(const char *path)
+{
+ char rp[PATH_MAX];
+
+ if (!realpath(path, rp)) return;
+ if (eina_hash_find(change_monitors, rp)) return;
+ eina_hash_add(change_monitors, rp,
+ ecore_file_monitor_add(rp,
+ efreet_desktop_changes_cb,
+ NULL));
+}
+
+static void
+efreet_desktop_changes_cb(void *data __UNUSED__, Ecore_File_Monitor *em __UNUSED__,
+ Ecore_File_Event event, const char *path)
+{
+ const char *ext;
+
+ /* TODO: If we get a stale symlink, we need to rerun cache creation */
+ /* TODO: Check for desktop*.cache, as this will be created when app is installed */
+ /* TODO: Do efreet_cache_icon_update() when app is installed, as it has the same
+ * symlink problem */
+ switch (event)
+ {
+ case ECORE_FILE_EVENT_NONE:
+ /* noop */
+ break;
+
+ case ECORE_FILE_EVENT_CREATED_FILE:
+ case ECORE_FILE_EVENT_DELETED_FILE:
+ case ECORE_FILE_EVENT_MODIFIED:
+ case ECORE_FILE_EVENT_CLOSED:
+ ext = strrchr(path, '.');
+ if (ext && (!strcmp(ext, ".desktop") || !strcmp(ext, ".directory")))
+ efreet_cache_desktop_update();
+ break;
+
+ case ECORE_FILE_EVENT_DELETED_SELF:
+ case ECORE_FILE_EVENT_DELETED_DIRECTORY:
+ eina_hash_del_by_key(change_monitors, path);
+ efreet_cache_desktop_update();
+ break;
+
+ case ECORE_FILE_EVENT_CREATED_DIRECTORY:
+ efreet_desktop_changes_monitor_add(path);
+ efreet_cache_desktop_update();
+ break;
+ }
+}