summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-29 23:04:40 +0000
committerGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-29 23:04:40 +0000
commit4bc0210bd31ed1de6554441562bd93ea863ee9d9 (patch)
tree5d83be12538f8c8d3816bbf65916ce383d050c2e /src/lib
parent727ddbeaf0c53f31cd62c254fdebe26823d537eb (diff)
efl: merge efreet.
seems to be fine, pass distcheck and friends. please report. changes: - documentation hierarchy fixes - replaced __UNUSED__ with EINA_UNUSED - replaced PKG_DATA_DIR with PACKAGE_DATA_DIR"/efreet" SVN revision: 81889
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/efreet/Efreet.h152
-rw-r--r--src/lib/efreet/Efreet_Mime.h129
-rw-r--r--src/lib/efreet/Efreet_Trash.h104
-rw-r--r--src/lib/efreet/efreet.c368
-rw-r--r--src/lib/efreet/efreet_alloca.h30
-rw-r--r--src/lib/efreet/efreet_base.c539
-rw-r--r--src/lib/efreet/efreet_base.h281
-rw-r--r--src/lib/efreet/efreet_cache.c1181
-rw-r--r--src/lib/efreet/efreet_cache_private.h60
-rw-r--r--src/lib/efreet/efreet_copy.h10
-rw-r--r--src/lib/efreet/efreet_desktop.c967
-rw-r--r--src/lib/efreet/efreet_desktop.h371
-rw-r--r--src/lib/efreet/efreet_desktop_command.c903
-rw-r--r--src/lib/efreet/efreet_icon.c796
-rw-r--r--src/lib/efreet/efreet_icon.h250
-rw-r--r--src/lib/efreet/efreet_ini.c578
-rw-r--r--src/lib/efreet/efreet_ini.h182
-rw-r--r--src/lib/efreet/efreet_menu.c3829
-rw-r--r--src/lib/efreet/efreet_menu.h139
-rw-r--r--src/lib/efreet/efreet_mime.c1612
-rw-r--r--src/lib/efreet/efreet_private.h231
-rw-r--r--src/lib/efreet/efreet_trash.c288
-rw-r--r--src/lib/efreet/efreet_uri.c119
-rw-r--r--src/lib/efreet/efreet_uri.h63
-rw-r--r--src/lib/efreet/efreet_utils.c474
-rw-r--r--src/lib/efreet/efreet_utils.h158
-rw-r--r--src/lib/efreet/efreet_xml.c609
-rw-r--r--src/lib/efreet/efreet_xml.h64
28 files changed, 14487 insertions, 0 deletions
diff --git a/src/lib/efreet/Efreet.h b/src/lib/efreet/Efreet.h
new file mode 100644
index 0000000..ae1ec18
--- /dev/null
+++ b/src/lib/efreet/Efreet.h
@@ -0,0 +1,152 @@
1#ifndef EFREET_H
2#define EFREET_H
3
4/**
5 * @file Efreet.h
6 * @brief The file that must be included by any project wishing to use
7 * Efreet. Efreet.h provides all of the necessary headers and includes to
8 * work with Efreet.
9 */
10
11/**
12 * @page efreet_main Efreet
13 *
14 * @section toc Table of Contents
15 *
16 * @li @ref efreet_main_intro
17 * @li @ref efreet_main_compiling
18 * @li @ref efreet_main_next_steps
19 *
20 * @section efreet_main_intro Introduction
21 *
22 * Efreet is a library designed to help apps work several of the
23 * Freedesktop.org standards regarding Icons, Desktop files and Menus. To
24 * that end it implements the following specifications:
25 *
26 * @li XDG Base Directory Specification
27 * @li Icon Theme Specification
28 * @li Desktop Entry Specification
29 * @li Desktop Menu Specification
30 * @li FDO URI Specification
31 * @li Shared Mime Info Specification
32 * @li Trash Specification
33 *
34 * @section efreet_main_compiling How to compile
35 *
36 * Efreet is a library your application links to. The procedure for
37 * this is very simple. You simply have to compile your application
38 * with the appropriate compiler flags that the @c pkg-config script
39 * outputs. Mime and Thrash are separated modules. For example, to
40 * compile with mime support:
41 *
42 * Compiling C or C++ files into object files:
43 *
44 * @verbatim
45 gcc -c -o main.o main.c `pkg-config --cflags efreet efreet-mime`
46 @endverbatim
47 *
48 * Linking object files into a binary executable:
49 *
50 * @verbatim
51 gcc -o my_application main.o `pkg-config --libs efreet efreet-mime`
52 @endverbatim
53 *
54 * See @ref pkgconfig
55 *
56 * @section efreet_main_next_steps Next Steps
57 *
58 * After you understood what Efreet is and installed it in your system
59 * you should proceed understanding the programming interface.
60 *
61 * Recommended reading:
62 *
63 * @li @ref Efreet_Base for base directory specification (XDG variables).
64 * @li @ref Efreet_Desktop to access .desktop files
65 * @li @ref Efreet_Menu to access menus of .desktop files
66 * @li @ref Efreet_Mime to identify files based on extension or header.
67 * @li @ref Efreet_Trash to access file trash implementation.
68 * @li @ref Efreet_Ini for parsing INI-like key-value files.
69 * @li @ref Efreet_Uri for URI parsing and encoding.
70 * @li @ref Efreet_Utils general utilities.
71 *
72 */
73
74#include <Eina.h>
75
76#ifdef EAPI
77# undef EAPI
78#endif
79
80#ifdef _WIN32
81# ifdef EFL_EFREET_BUILD
82# ifdef DLL_EXPORT
83# define EAPI __declspec(dllexport)
84# else
85# define EAPI
86# endif /* ! DLL_EXPORT */
87# else
88# define EAPI __declspec(dllimport)
89# endif /* ! EFL_EFREET_BUILD */
90#else
91# ifdef __GNUC__
92# if __GNUC__ >= 4
93# define EAPI __attribute__ ((visibility("default")))
94# else
95# define EAPI
96# endif
97# else
98# define EAPI
99# endif
100#endif
101
102#ifdef __cplusplus
103extern "C" {
104#endif
105
106#define EFREET_VERSION_MAJOR 1
107#define EFREET_VERSION_MINOR 8
108
109 typedef struct _Efreet_Version
110 {
111 int major;
112 int minor;
113 int micro;
114 int revision;
115 } Efreet_Version;
116
117 EAPI extern Efreet_Version *efreet_version;
118
119#include "efreet_base.h"
120#include "efreet_ini.h"
121#include "efreet_icon.h"
122#include "efreet_desktop.h"
123#include "efreet_menu.h"
124#include "efreet_utils.h"
125#include "efreet_uri.h"
126
127/**
128 * @return Value > @c 0 if the initialization was successful, @c 0 otherwise.
129 * @brief Initializes the Efreet system
130 */
131EAPI int efreet_init(void);
132
133/**
134 * @return The number of times the init function has been called minus the
135 * corresponding init call.
136 * @brief Shuts down Efreet if a balanced number of init/shutdown calls have
137 * been made
138 */
139EAPI int efreet_shutdown(void);
140
141/**
142 * @brief Resets language dependent variables and resets language dependent
143 * caches This must be called whenever the locale is changed.
144 * @since 1.7
145 */
146EAPI void efreet_lang_reset(void);
147
148#ifdef __cplusplus
149}
150#endif
151
152#endif
diff --git a/src/lib/efreet/Efreet_Mime.h b/src/lib/efreet/Efreet_Mime.h
new file mode 100644
index 0000000..5bfd418
--- /dev/null
+++ b/src/lib/efreet/Efreet_Mime.h
@@ -0,0 +1,129 @@
1#ifndef EFREET_MIME_H
2#define EFREET_MIME_H
3
4/**
5 * @file Efreet_Mime.h
6 * @brief The file that must be included by any project wishing to use
7 * @addtogroup Efreet_Mime Efreet_Mime: The XDG Shared Mime Info standard
8 * Efreet Mime is a library designed to help apps work with the
9 * Freedesktop.org Shared Mime Info standard.
10 * Efreet_Mime.h provides all of the necessary headers and
11 * includes to work with Efreet_Mime.
12 *
13 * @ingroup Efreet
14 * @{
15 */
16
17#ifdef EAPI
18# undef EAPI
19#endif
20
21#ifdef _WIN32
22# ifdef EFL_EFREET_MIME_BUILD
23# ifdef DLL_EXPORT
24# define EAPI __declspec(dllexport)
25# else
26# define EAPI
27# endif /* ! DLL_EXPORT */
28# else
29# define EAPI __declspec(dllimport)
30# endif /* ! EFL_EFREET_MIME_BUILD */
31#else
32# ifdef __GNUC__
33# if __GNUC__ >= 4
34# define EAPI __attribute__ ((visibility("default")))
35# else
36# define EAPI
37# endif
38# else
39# define EAPI
40# endif
41#endif
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47
48/**
49 * @return @c 1 on success or @c 0 on failure.
50 * @brief Initializes the efreet mime settings
51 */
52EAPI int efreet_mime_init(void);
53
54/**
55 * @return The number of times the init function has been called minus the
56 * corresponding init call.
57 * @brief Shuts down Efreet mime settings system if a balanced number of
58 * init/shutdown calls have been made
59 */
60EAPI int efreet_mime_shutdown(void);
61
62/**
63 * @param file The file to find the mime type
64 * @return Mime type as a string.
65 * @brief Retrieve the mime type of a file
66 */
67EAPI const char *efreet_mime_type_get(const char *file);
68
69/**
70 * @param file The file to check the mime type
71 * @return Mime type as a string.
72 * @brief Retrieve the mime type of a file using magic
73 */
74EAPI const char *efreet_mime_magic_type_get(const char *file);
75
76/**
77 * @param file The file to check the mime type
78 * @return Mime type as a string.
79 * @brief Retrieve the mime type of a file using globs
80 */
81EAPI const char *efreet_mime_globs_type_get(const char *file);
82
83/**
84 * @param file The file to check the mime type
85 * @return Mime type as a string.
86 * @brief Retrieve the special mime type of a file
87 */
88EAPI const char *efreet_mime_special_type_get(const char *file);
89
90/**
91 * @param file The file to check the mime type
92 * @return Mime type as a string.
93 * @brief Retrieve the fallback mime type of a file.
94 */
95EAPI const char *efreet_mime_fallback_type_get(const char *file);
96
97
98/**
99 * @param mime The name of the mime type
100 * @param theme The name of the theme to search icons in
101 * @param size The wanted size of the icon
102 * @return Mime type icon path as a string.
103 * @brief Retrieve the mime type icon for a file.
104 */
105EAPI const char *efreet_mime_type_icon_get(const char *mime, const char *theme,
106 unsigned int size);
107
108/**
109 * @brief Clear mime icons mapping cache
110 */
111EAPI void efreet_mime_type_cache_clear(void);
112
113/**
114 * @brief Flush mime icons mapping cache
115 *
116 * Flush timeout is defined at compile time by
117 * EFREET_MIME_ICONS_FLUSH_TIMEOUT
118 */
119EAPI void efreet_mime_type_cache_flush(void);
120
121/**
122 * @}
123 */
124
125#ifdef __cplusplus
126}
127#endif
128
129#endif
diff --git a/src/lib/efreet/Efreet_Trash.h b/src/lib/efreet/Efreet_Trash.h
new file mode 100644
index 0000000..a32be65
--- /dev/null
+++ b/src/lib/efreet/Efreet_Trash.h
@@ -0,0 +1,104 @@
1#ifndef EFREET_TRASH_H
2#define EFREET_TRASH_H
3
4#ifdef EAPI
5# undef EAPI
6#endif
7
8#ifdef _WIN32
9# ifdef EFL_EFREET_TRASH_BUILD
10# ifdef DLL_EXPORT
11# define EAPI __declspec(dllexport)
12# else
13# define EAPI
14# endif /* ! DLL_EXPORT */
15# else
16# define EAPI __declspec(dllimport)
17# endif /* ! EFL_EFREET_TRASH_BUILD */
18#else
19# ifdef __GNUC__
20# if __GNUC__ >= 4
21# define EAPI __attribute__ ((visibility("default")))
22# else
23# define EAPI
24# endif
25# else
26# define EAPI
27# endif
28#endif
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34/**
35 * @file Efreet_Trash.h
36 * @brief Contains the methods used to support the FDO trash specification.
37 * @addtogroup Efreet_Trash Efreet_Trash: The XDG Trash Specification
38 * Efreet_Trash.h provides all of the necessary headers and includes to
39 * work with Efreet_Trash.
40 *
41 * @ingroup Efreet
42 * @{
43 */
44
45/**
46 * @return @c 1 on success or @c 0 on failure.
47 * @brief Initializes the efreet trash system
48 */
49EAPI int efreet_trash_init(void);
50
51/**
52 * @return No value.
53 * @brief Cleans up the efreet trash system
54 */
55EAPI int efreet_trash_shutdown(void);
56
57/**
58 * @return The XDG Trash local directory or @c NULL on errors.
59 * Return value must be freed with eina_stringshare_del.
60 * @brief Retrieves the XDG Trash local directory
61 */
62EAPI const char *efreet_trash_dir_get(const char *for_file);
63
64/**
65 * @param uri The local uri to move in the trash
66 * @param force_delete If you set this to @c 1 than files on different filesystems
67 * will be deleted permanently
68 * @return @c 1 on success, @c 0 on failure or @c -1 in case the uri is not on
69 * the same filesystem and force_delete is not set.
70 * @brief This function try to move the given uri to the trash. Files on
71 * different filesystem can't be moved to trash. If force_delete
72 * is @c 0 than non-local files will be ignored and @c -1 is returned, if you set
73 * force_delete to @c 1 non-local files will be deleted without asking.
74 */
75EAPI int efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete);
76
77/**
78 * @return A list of strings with filename (remember to free the list
79 * when you don't need anymore).
80 * @brief List all the files and directory currently inside the trash.
81 */
82EAPI Eina_List *efreet_trash_ls(void);
83
84/**
85 * @return @c 1 if the trash is empty or @c 0 if some file are in.
86 * @brief Check if the trash is currently empty
87 */
88EAPI int efreet_trash_is_empty(void);
89
90/**
91 * @return @c 1 on success or @c 0 on failure.
92 * @brief Delete all the files inside the trash.
93 */
94EAPI int efreet_trash_empty_trash(void);
95
96/**
97 * @}
98 */
99
100#ifdef __cplusplus
101}
102#endif
103
104#endif
diff --git a/src/lib/efreet/efreet.c b/src/lib/efreet/efreet.c
new file mode 100644
index 0000000..fcc0cfb
--- /dev/null
+++ b/src/lib/efreet/efreet.c
@@ -0,0 +1,368 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "efreet_alloca.h"
6
7#include <unistd.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10
11#include <Eet.h>
12#include <Ecore.h>
13#include <Ecore_File.h>
14
15/* define macros and variable for using the eina logging system */
16#define EFREET_MODULE_LOG_DOM /* no logging in this file */
17
18#include "Efreet.h"
19#include "efreet_private.h"
20#include "efreet_xml.h"
21
22/*
23 * Needs EAPI because of helper binaries
24 */
25EAPI int efreet_cache_update = 1;
26
27static int _efreet_init_count = 0;
28static int efreet_parsed_locale = 0;
29static const char *efreet_lang = NULL;
30static const char *efreet_lang_country = NULL;
31static const char *efreet_lang_modifier = NULL;
32static const char *efreet_language = NULL;
33static void efreet_parse_locale(void);
34static int efreet_parse_locale_setting(const char *env);
35
36#ifndef _WIN32
37static uid_t ruid;
38static uid_t rgid;
39#endif
40
41EAPI int
42efreet_init(void)
43{
44#ifndef _WIN32
45 char *tmp;
46#endif
47
48 if (++_efreet_init_count != 1)
49 return _efreet_init_count;
50
51#ifndef _WIN32
52 /* Find users real uid and gid */
53 tmp = getenv("SUDO_UID");
54 if (tmp)
55 ruid = strtoul(tmp, NULL, 10);
56 else
57 ruid = getuid();
58
59 tmp = getenv("SUDO_GID");
60 if (tmp)
61 rgid = strtoul(tmp, NULL, 10);
62 else
63 rgid = getgid();
64#endif
65
66 if (!eina_init())
67 return --_efreet_init_count;
68 if (!eet_init())
69 goto shutdown_eina;
70 if (!ecore_init())
71 goto shutdown_eet;
72 if (!ecore_file_init())
73 goto shutdown_ecore;
74
75 if (!efreet_base_init())
76 goto shutdown_ecore_file;
77
78 if (!efreet_cache_init())
79 goto shutdown_efreet_base;
80
81 if (!efreet_xml_init())
82 goto shutdown_efreet_cache;
83
84 if (!efreet_icon_init())
85 goto shutdown_efreet_xml;
86
87 if (!efreet_ini_init())
88 goto shutdown_efreet_icon;
89
90 if (!efreet_desktop_init())
91 goto shutdown_efreet_ini;
92
93 if (!efreet_menu_init())
94 goto shutdown_efreet_desktop;
95
96 if (!efreet_util_init())
97 goto shutdown_efreet_menu;
98
99#ifdef ENABLE_NLS
100 bindtextdomain(PACKAGE, LOCALE_DIR);
101 bind_textdomain_codeset(PACKAGE, "UTF-8");
102#endif
103
104 return _efreet_init_count;
105
106shutdown_efreet_menu:
107 efreet_menu_shutdown();
108shutdown_efreet_desktop:
109 efreet_desktop_shutdown();
110shutdown_efreet_ini:
111 efreet_ini_shutdown();
112shutdown_efreet_icon:
113 efreet_icon_shutdown();
114shutdown_efreet_xml:
115 efreet_xml_shutdown();
116shutdown_efreet_cache:
117 efreet_cache_shutdown();
118shutdown_efreet_base:
119 efreet_base_shutdown();
120shutdown_ecore_file:
121 ecore_file_shutdown();
122shutdown_ecore:
123 ecore_shutdown();
124shutdown_eet:
125 eet_shutdown();
126shutdown_eina:
127 eina_shutdown();
128
129 return --_efreet_init_count;
130}
131
132EAPI int
133efreet_shutdown(void)
134{
135 if (_efreet_init_count <= 0)
136 {
137 EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
138 return 0;
139 }
140 if (--_efreet_init_count != 0)
141 return _efreet_init_count;
142
143 efreet_util_shutdown();
144 efreet_menu_shutdown();
145 efreet_desktop_shutdown();
146 efreet_ini_shutdown();
147 efreet_icon_shutdown();
148 efreet_xml_shutdown();
149 efreet_cache_shutdown();
150 efreet_base_shutdown();
151
152 IF_RELEASE(efreet_lang);
153 IF_RELEASE(efreet_lang_country);
154 IF_RELEASE(efreet_lang_modifier);
155 IF_RELEASE(efreet_language);
156 efreet_parsed_locale = 0; /* reset this in case they init efreet again */
157
158 ecore_file_shutdown();
159 ecore_shutdown();
160 eet_shutdown();
161 eina_shutdown();
162
163 return _efreet_init_count;
164}
165
166EAPI void
167efreet_lang_reset(void)
168{
169 IF_RELEASE(efreet_lang);
170 IF_RELEASE(efreet_lang_country);
171 IF_RELEASE(efreet_lang_modifier);
172 IF_RELEASE(efreet_language);
173 efreet_parsed_locale = 0; /* reset this in case they init efreet again */
174
175 efreet_dirs_reset();
176 efreet_parse_locale();
177 efreet_cache_desktop_close();
178 efreet_cache_desktop_build();
179}
180
181/**
182 * @internal
183 * @return Returns the current users language setting or NULL if none set
184 * @brief Retrieves the current language setting
185 */
186const char *
187efreet_lang_get(void)
188{
189 if (efreet_parsed_locale) return efreet_lang;
190
191 efreet_parse_locale();
192 return efreet_lang;
193}
194
195/**
196 * @internal
197 * @return Returns the current language country setting or NULL if none set
198 * @brief Retrieves the current country setting for the current language or
199 */
200const char *
201efreet_lang_country_get(void)
202{
203 if (efreet_parsed_locale) return efreet_lang_country;
204
205 efreet_parse_locale();
206 return efreet_lang_country;
207}
208
209/**
210 * @internal
211 * @return Returns the current language modifier setting or NULL if none
212 * set.
213 * @brief Retrieves the modifier setting for the language.
214 */
215const char *
216efreet_lang_modifier_get(void)
217{
218 if (efreet_parsed_locale) return efreet_lang_modifier;
219
220 efreet_parse_locale();
221 return efreet_lang_modifier;
222}
223
224EAPI const char *
225efreet_language_get(void)
226{
227 if (efreet_parsed_locale) return efreet_language;
228
229 efreet_parse_locale();
230 return efreet_language;
231}
232
233/**
234 * @internal
235 * @return Returns no value
236 * @brief Parses out the language, country and modifer setting from the
237 * LC_MESSAGES environment variable
238 */
239static void
240efreet_parse_locale(void)
241{
242 efreet_parsed_locale = 1;
243
244 if (efreet_parse_locale_setting("LANG"))
245 return;
246
247 if (efreet_parse_locale_setting("LC_ALL"))
248 return;
249
250 if (efreet_parse_locale_setting("LC_MESSAGES"))
251 return;
252
253 efreet_language = eina_stringshare_add("C");
254}
255
256/**
257 * @internal
258 * @param env The environment variable to grab
259 * @return Returns 1 if we parsed something of @a env, 0 otherwise
260 * @brief Tries to parse the lang settings out of the given environment
261 * variable
262 */
263static int
264efreet_parse_locale_setting(const char *env)
265{
266 int found = 0;
267 char *setting;
268 char *p;
269 size_t len;
270
271 p = getenv(env);
272 if (!p) return 0;
273 len = strlen(p) + 1;
274 setting = alloca(len);
275 memcpy(setting, p, len);
276
277 /* pull the modifier off the end */
278 p = strrchr(setting, '@');
279 if (p)
280 {
281 *p = '\0';
282 efreet_lang_modifier = eina_stringshare_add(p + 1);
283 found = 1;
284 }
285
286 /* if there is an encoding we ignore it */
287 p = strrchr(setting, '.');
288 if (p) *p = '\0';
289
290 /* get the country if available */
291 p = strrchr(setting, '_');
292 if (p)
293 {
294 *p = '\0';
295 efreet_lang_country = eina_stringshare_add(p + 1);
296 found = 1;
297 }
298
299 if (*setting != '\0')
300 {
301 efreet_lang = eina_stringshare_add(setting);
302 found = 1;
303 }
304
305 if (found)
306 efreet_language = eina_stringshare_add(getenv(env));
307 return found;
308}
309
310/**
311 * @internal
312 * @param buffer The destination buffer
313 * @param size The destination buffer size
314 * @param strs The strings to concatenate together
315 * @return Returns the size of the string in @a buffer
316 * @brief Concatenates the strings in @a strs into the given @a buffer not
317 * exceeding the given @a size.
318 */
319size_t
320efreet_array_cat(char *buffer, size_t size, const char *strs[])
321{
322 int i;
323 size_t n;
324 for (i = 0, n = 0; n < size && strs[i]; i++)
325 {
326 n += eina_strlcpy(buffer + n, strs[i], size - n);
327 }
328 return n;
329}
330
331#ifndef _WIN32
332EAPI void
333efreet_fsetowner(int fd)
334{
335 struct stat st;
336
337 if (fd < 0) return;
338 if (fstat(fd, &st) < 0) return;
339 if (st.st_uid == ruid) return;
340
341 if (fchown(fd, ruid, rgid) != 0) return;
342}
343#else
344EAPI void
345efreet_fsetowner(int fd EINA_UNUSED)
346{
347}
348#endif
349
350#ifndef _WIN32
351EAPI void
352efreet_setowner(const char *path)
353{
354 EINA_SAFETY_ON_NULL_RETURN(path);
355
356 int fd;
357
358 fd = open(path, O_RDONLY);
359 if (fd < 0) return;
360 efreet_fsetowner(fd);
361 close(fd);
362}
363#else
364EAPI void
365efreet_setowner(const char *path EINA_UNUSED)
366{
367}
368#endif
diff --git a/src/lib/efreet/efreet_alloca.h b/src/lib/efreet/efreet_alloca.h
new file mode 100644
index 0000000..58a7398
--- /dev/null
+++ b/src/lib/efreet/efreet_alloca.h
@@ -0,0 +1,30 @@
1#ifndef EFREET_ALLOCA_H
2#define EFREET_ALLOCA_H
3
4#ifdef STDC_HEADERS
5# include <stdlib.h>
6# include <stddef.h>
7#else
8# ifdef HAVE_STDLIB_H
9# include <stdlib.h>
10# endif
11#endif
12#ifdef HAVE_ALLOCA_H
13# include <alloca.h>
14#elif !defined alloca
15# ifdef __GNUC__
16# define alloca __builtin_alloca
17# elif defined _AIX
18# define alloca __alloca
19# elif defined _MSC_VER
20# include <malloc.h>
21# define alloca _alloca
22# elif !defined HAVE_ALLOCA
23# ifdef __cplusplus
24extern "C"
25# endif
26void *alloca (size_t);
27# endif
28#endif
29
30#endif
diff --git a/src/lib/efreet/efreet_base.c b/src/lib/efreet/efreet_base.c
new file mode 100644
index 0000000..0c0b286
--- /dev/null
+++ b/src/lib/efreet/efreet_base.c
@@ -0,0 +1,539 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "efreet_alloca.h"
6
7#include <unistd.h>
8#include <ctype.h>
9
10#ifdef _WIN32
11# include <winsock2.h>
12#endif
13
14/* define macros and variable for using the eina logging system */
15#define EFREET_MODULE_LOG_DOM _efreet_base_log_dom
16static int _efreet_base_log_dom = -1;
17
18#include "Efreet.h"
19#include "efreet_private.h"
20
21#include <Ecore_File.h>
22
23static Efreet_Version _version = { VMAJ, VMIN, VMIC, VREV };
24EAPI Efreet_Version *efreet_version = &_version;
25
26#ifdef _WIN32
27# define EFREET_PATH_SEP ';'
28#else
29# define EFREET_PATH_SEP ':'
30#endif
31
32static const char *efreet_home_dir = NULL;
33static const char *xdg_data_home = NULL;
34static const char *xdg_config_home = NULL;
35static const char *xdg_cache_home = NULL;
36static const char *xdg_runtime_dir = NULL;
37static Eina_List *xdg_data_dirs = NULL;
38static Eina_List *xdg_config_dirs = NULL;
39static const char *xdg_desktop_dir = NULL;
40static const char *xdg_download_dir = NULL;
41static const char *xdg_templates_dir = NULL;
42static const char *xdg_publicshare_dir = NULL;
43static const char *xdg_documents_dir = NULL;
44static const char *xdg_music_dir = NULL;
45static const char *xdg_pictures_dir = NULL;
46static const char *xdg_videos_dir = NULL;
47static const char *hostname = NULL;
48
49static const char *efreet_dir_get(const char *key, const char *fallback);
50static Eina_List *efreet_dirs_get(const char *key,
51 const char *fallback);
52static const char *efreet_user_dir_get(const char *key, const char *fallback);
53
54/**
55 * @internal
56 * @return Returns @c 1 on success or @c 0 on failure
57 * @brief Initializes the efreet base settings
58 */
59int
60efreet_base_init(void)
61{
62 _efreet_base_log_dom = eina_log_domain_register
63 ("efreet_base", EFREET_DEFAULT_LOG_COLOR);
64 if (_efreet_base_log_dom < 0)
65 {
66 EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_base.\n");
67 return 0;
68 }
69 return 1;
70}
71
72/**
73 * @internal
74 * @return Returns no value
75 * @brief Cleans up the efreet base settings system
76 */
77void
78efreet_base_shutdown(void)
79{
80 IF_RELEASE(efreet_home_dir);
81 IF_RELEASE(xdg_desktop_dir);
82 IF_RELEASE(xdg_download_dir);
83 IF_RELEASE(xdg_templates_dir);
84 IF_RELEASE(xdg_publicshare_dir);
85 IF_RELEASE(xdg_documents_dir);
86 IF_RELEASE(xdg_music_dir);
87 IF_RELEASE(xdg_pictures_dir);
88 IF_RELEASE(xdg_videos_dir);
89
90 IF_RELEASE(xdg_data_home);
91 IF_RELEASE(xdg_config_home);
92 IF_RELEASE(xdg_cache_home);
93 IF_RELEASE(xdg_runtime_dir);
94
95 IF_FREE_LIST(xdg_data_dirs, eina_stringshare_del);
96 IF_FREE_LIST(xdg_config_dirs, eina_stringshare_del);
97
98 IF_RELEASE(hostname);
99
100 eina_log_domain_unregister(_efreet_base_log_dom);
101 _efreet_base_log_dom = -1;
102}
103
104/**
105 * @internal
106 * @return Returns the users home directory
107 * @brief Gets the users home directory and returns it.
108 */
109const char *
110efreet_home_dir_get(void)
111{
112 if (efreet_home_dir) return efreet_home_dir;
113
114 efreet_home_dir = getenv("HOME");
115#ifdef _WIN32
116 if (!efreet_home_dir || efreet_home_dir[0] == '\0')
117 efreet_home_dir = getenv("USERPROFILE");
118#endif
119 if (!efreet_home_dir || efreet_home_dir[0] == '\0')
120 efreet_home_dir = "/tmp";
121
122 efreet_home_dir = eina_stringshare_add(efreet_home_dir);
123
124 return efreet_home_dir;
125}
126
127EAPI const char *
128efreet_desktop_dir_get(void)
129{
130 if (xdg_desktop_dir) return xdg_desktop_dir;
131 xdg_desktop_dir = efreet_user_dir_get("XDG_DESKTOP_DIR", _("Desktop"));
132 return xdg_desktop_dir;
133}
134
135EAPI const char *
136efreet_download_dir_get(void)
137{
138 if (xdg_download_dir) return xdg_download_dir;
139 xdg_download_dir = efreet_user_dir_get("XDG_DOWNLOAD_DIR", _("Downloads"));
140 return xdg_download_dir;
141}
142
143EAPI const char *
144efreet_templates_dir_get(void)
145{
146 if (xdg_templates_dir) return xdg_templates_dir;
147 xdg_templates_dir = efreet_user_dir_get("XDG_TEMPLATES_DIR",
148 _("Templates"));
149 return xdg_templates_dir;
150}
151
152EAPI const char *
153efreet_public_share_dir_get(void)
154{
155 if (xdg_publicshare_dir) return xdg_publicshare_dir;
156 xdg_publicshare_dir = efreet_user_dir_get("XDG_PUBLICSHARE_DIR",
157 _("Public"));
158 return xdg_publicshare_dir;
159}
160
161EAPI const char *
162efreet_documents_dir_get(void)
163{
164 if (xdg_documents_dir) return xdg_documents_dir;
165 xdg_documents_dir = efreet_user_dir_get("XDG_DOCUMENTS_DIR",
166 _("Documents"));
167 return xdg_documents_dir;
168}
169
170EAPI const char *
171efreet_music_dir_get(void)
172{
173 if (xdg_music_dir) return xdg_music_dir;
174 xdg_music_dir = efreet_user_dir_get("XDG_MUSIC_DIR", _("Music"));
175 return xdg_music_dir;
176}
177
178EAPI const char *
179efreet_pictures_dir_get(void)
180{
181 if (xdg_pictures_dir) return xdg_pictures_dir;
182 xdg_pictures_dir = efreet_user_dir_get("XDG_PICTURES_DIR", _("Pictures"));
183 return xdg_pictures_dir;
184}
185
186EAPI const char *
187efreet_videos_dir_get(void)
188{
189 if (xdg_videos_dir) return xdg_videos_dir;
190 xdg_videos_dir = efreet_user_dir_get("XDG_VIDEOS_DIR", _("Videos"));
191 return xdg_videos_dir;
192}
193
194EAPI const char *
195efreet_data_home_get(void)
196{
197 if (xdg_data_home) return xdg_data_home;
198 xdg_data_home = efreet_dir_get("XDG_DATA_HOME", "/.local/share");
199 return xdg_data_home;
200}
201
202EAPI Eina_List *
203efreet_data_dirs_get(void)
204{
205#ifdef _WIN32
206 char buf[4096];
207#endif
208
209 if (xdg_data_dirs) return xdg_data_dirs;
210
211#ifdef _WIN32
212 snprintf(buf, 4096, "%s\\Efl;" PACKAGE_DATA_DIR ";/usr/share;/usr/local/share", getenv("APPDATA"));
213 xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS", buf);
214#else
215 xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS",
216 PACKAGE_DATA_DIR ":/usr/share:/usr/local/share");
217#endif
218 return xdg_data_dirs;
219}
220
221EAPI const char *
222efreet_config_home_get(void)
223{
224 if (xdg_config_home) return xdg_config_home;
225 xdg_config_home = efreet_dir_get("XDG_CONFIG_HOME", "/.config");
226 return xdg_config_home;
227}
228
229EAPI Eina_List *
230efreet_config_dirs_get(void)
231{
232 if (xdg_config_dirs) return xdg_config_dirs;
233 xdg_config_dirs = efreet_dirs_get("XDG_CONFIG_DIRS", "/etc/xdg");
234 return xdg_config_dirs;
235}
236
237EAPI const char *
238efreet_cache_home_get(void)
239{
240 if (xdg_cache_home) return xdg_cache_home;
241 xdg_cache_home = efreet_dir_get("XDG_CACHE_HOME", "/.cache");
242 return xdg_cache_home;
243}
244
245EAPI const char *
246efreet_runtime_dir_get(void)
247{
248 struct stat st;
249 if (xdg_runtime_dir) return xdg_runtime_dir;
250 xdg_runtime_dir = efreet_dir_get("XDG_RUNTIME_DIR", "/tmp");
251 if (stat(xdg_runtime_dir, &st) == -1)
252 {
253 ERR("$XDG_RUNTIME_DIR did not exist, creating '%s' (breaks spec)",
254 xdg_runtime_dir);
255 if (ecore_file_mkpath(xdg_runtime_dir))
256 chmod(xdg_runtime_dir, 0700);
257 else
258 {
259 CRITICAL("Failed to create XDG_RUNTIME_DIR=%s", xdg_runtime_dir);
260 eina_stringshare_replace(&xdg_runtime_dir, NULL);
261 }
262 }
263 else if (!S_ISDIR(st.st_mode))
264 {
265 CRITICAL("XDG_RUNTIME_DIR=%s is not a directory!", xdg_runtime_dir);
266 eina_stringshare_replace(&xdg_runtime_dir, NULL);
267 }
268 else if ((st.st_mode & 0777) != 0700)
269 {
270 ERR("XDG_RUNTIME_DIR=%s is mode %o, changing to 0700",
271 xdg_runtime_dir, st.st_mode & 0777);
272 if (chmod(xdg_runtime_dir, 0700) != 0)
273 {
274 CRITICAL("Cannot fix XDG_RUNTIME_DIR=%s incorrect mode %o: %s",
275 xdg_runtime_dir, st.st_mode & 0777, strerror(errno));
276 eina_stringshare_replace(&xdg_runtime_dir, NULL);
277 }
278 }
279
280 return xdg_runtime_dir;
281}
282
283EAPI const char *
284efreet_hostname_get(void)
285{
286 char buf[256];
287
288 if (hostname) return hostname;
289 if (gethostname(buf, sizeof(buf)) < 0)
290 hostname = eina_stringshare_add("");
291 else
292 hostname = eina_stringshare_add(buf);
293 return hostname;
294}
295
296/**
297 * @internal
298 * @param user_dir The user directory to work with
299 * @param system_dirs The system directories to work with
300 * @param suffix The path suffix to add
301 * @return Returns the list of directories
302 * @brief Creates the list of directories based on the user
303 * dir, system dirs and given suffix.
304 *
305 * Needs EAPI because of helper binaries
306 */
307EAPI Eina_List *
308efreet_default_dirs_get(const char *user_dir, Eina_List *system_dirs,
309 const char *suffix)
310{
311 const char *xdg_dir;
312 char dir[PATH_MAX];
313 Eina_List *list = NULL;
314 Eina_List *l;
315
316 EINA_SAFETY_ON_NULL_RETURN_VAL(user_dir, NULL);
317 EINA_SAFETY_ON_NULL_RETURN_VAL(suffix, NULL);
318
319 snprintf(dir, sizeof(dir), "%s/%s", user_dir, suffix);
320 list = eina_list_append(list, eina_stringshare_add(dir));
321
322 EINA_LIST_FOREACH(system_dirs, l, xdg_dir)
323 {
324 snprintf(dir, sizeof(dir), "%s/%s", xdg_dir, suffix);
325 list = eina_list_append(list, eina_stringshare_add(dir));
326 }
327
328 return list;
329}
330
331void
332efreet_dirs_reset(void)
333{
334 eina_stringshare_replace(&xdg_desktop_dir, NULL);
335 eina_stringshare_replace(&xdg_download_dir, NULL);
336 eina_stringshare_replace(&xdg_templates_dir, NULL);
337 eina_stringshare_replace(&xdg_publicshare_dir, NULL);
338 eina_stringshare_replace(&xdg_documents_dir, NULL);
339 eina_stringshare_replace(&xdg_music_dir, NULL);
340 eina_stringshare_replace(&xdg_pictures_dir, NULL);
341 eina_stringshare_replace(&xdg_videos_dir, NULL);
342}
343
344/**
345 * @internal
346 * @param key The environment key to lookup
347 * @param fallback The fallback value to use
348 * @return Returns the directory related to the given key or the fallback
349 * @brief This tries to determine the correct directory name given the
350 * environment key @a key and fallbacks @a fallback.
351 */
352static const char *
353efreet_dir_get(const char *key, const char *fallback)
354{
355 char *dir;
356 const char *t;
357
358 dir = getenv(key);
359 if (!dir || dir[0] == '\0')
360 {
361 int len;
362 const char *user;
363
364 user = efreet_home_dir_get();
365 len = strlen(user) + strlen(fallback) + 1;
366 dir = alloca(len);
367 snprintf(dir, len, "%s%s", user, fallback);
368
369 t = eina_stringshare_add(dir);
370 }
371 else t = eina_stringshare_add(dir);
372
373 return t;
374}
375
376/**
377 * @internal
378 * @param key The environment key to lookup
379 * @param fallback The fallback value to use
380 * @return Returns a list of directories specified by the given key @a key
381 * or from the list of fallbacks in @a fallback.
382 * @brief Creates a list of directories as given in the environment key @a
383 * key or from the fallbacks in @a fallback
384 */
385static Eina_List *
386efreet_dirs_get(const char *key, const char *fallback)
387{
388 Eina_List *dirs = NULL;
389 const char *path;
390 char *s, *p;
391 size_t len;
392
393 path = getenv(key);
394 if (!path || (path[0] == '\0')) path = fallback;
395
396 if (!path) return dirs;
397
398 len = strlen(path) + 1;
399 s = alloca(len);
400 memcpy(s, path, len);
401 p = strchr(s, EFREET_PATH_SEP);
402 while (p)
403 {
404 *p = '\0';
405 if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s))
406 {
407 char *tmp = eina_file_path_sanitize(s);
408 if (tmp)
409 {
410 dirs = eina_list_append(dirs, eina_stringshare_add(tmp));
411 free(tmp);
412 }
413 }
414
415 s = ++p;
416 p = strchr(s, EFREET_PATH_SEP);
417 }
418 if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s))
419 {
420 char *tmp = eina_file_path_sanitize(s);
421 if (tmp)
422 {
423 dirs = eina_list_append(dirs, eina_stringshare_add(tmp));
424 free(tmp);
425 }
426 }
427
428 return dirs;
429}
430
431static const char *
432efreet_env_expand(const char *in)
433{
434 Eina_Strbuf *sb;
435 const char *ret, *p, *e1 = NULL, *e2 = NULL, *val;
436 char *env;
437
438 if (!in) return NULL;
439 sb = eina_strbuf_new();
440 if (!sb) return NULL;
441
442 /* maximum length of any env var is the input string */
443 env = alloca(strlen(in) + 1);
444 for (p = in; *p; p++)
445 {
446 if (!e1)
447 {
448 if (*p == '$') e1 = p + 1;
449 else eina_strbuf_append_char(sb, *p);
450 }
451 else if (!(((*p >= 'a') && (*p <= 'z')) ||
452 ((*p >= 'A') && (*p <= 'Z')) ||
453 ((*p >= '0') && (*p <= '9')) ||
454 (*p == '_')))
455 {
456 size_t len;
457
458 e2 = p;
459 len = (size_t)(e2 - e1);
460 if (len > 0)
461 {
462 memcpy(env, e1, len);
463 env[len] = 0;
464 val = getenv(env);
465 if (val) eina_strbuf_append(sb, val);
466 }
467 e1 = NULL;
468 eina_strbuf_append_char(sb, *p);
469 }
470 }
471 ret = eina_stringshare_add(eina_strbuf_string_get(sb));
472 eina_strbuf_free(sb);
473 return ret;
474}
475
476/**
477 * @internal
478 * @param key The user-dirs key to lookup
479 * @param fallback The fallback value to use
480 * @return Returns the directory related to the given key or the fallback
481 * @brief This tries to determine the correct directory name given the
482 * user-dirs key @a key and fallbacks @a fallback.
483 */
484static const char *
485efreet_user_dir_get(const char *key, const char *fallback)
486{
487 Eina_File *file = NULL;
488 Eina_File_Line *line;
489 Eina_Iterator *it = NULL;
490 const char *config_home;
491 char path[PATH_MAX];
492 char *ret = NULL;
493
494 config_home = efreet_config_home_get();
495 snprintf(path, sizeof(path), "%s/user-dirs.dirs", config_home);
496
497 file = eina_file_open(path, EINA_FALSE);
498 if (!file) goto fallback;
499 it = eina_file_map_lines(file);
500 if (!it) goto fallback;
501 EINA_ITERATOR_FOREACH(it, line)
502 {
503 const char *eq, *end;
504
505 if (line->length < 3) continue;
506 if (line->start[0] == '#') continue;
507 if (strncmp(line->start, "XDG", 3)) continue;
508 eq = memchr(line->start, '=', line->length);
509 if (!eq) continue;
510 if (strncmp(key, line->start, eq - line->start)) continue;
511 if (++eq >= line->end) continue;
512 if (*eq == '"')
513 {
514 if (++eq >= line->end) continue;
515 end = memchr(eq, '"', line->end - eq);
516 }
517 else
518 {
519 end = line->end;
520 while (isspace(*end)) end--;
521 }
522 if (!end) continue;
523 ret = alloca(end - eq + 1);
524 memcpy(ret, eq, end - eq);
525 ret[end - eq] = '\0';
526 break;
527 }
528fallback:
529 if (it) eina_iterator_free(it);
530 if (file) eina_file_close(file);
531 if (!ret)
532 {
533 const char *home;
534 home = efreet_home_dir_get();
535 ret = alloca(strlen(home) + strlen(fallback) + 2);
536 sprintf(ret, "%s/%s", home, fallback);
537 }
538 return efreet_env_expand(ret);
539}
diff --git a/src/lib/efreet/efreet_base.h b/src/lib/efreet/efreet_base.h
new file mode 100644
index 0000000..ca011d9
--- /dev/null
+++ b/src/lib/efreet/efreet_base.h
@@ -0,0 +1,281 @@
1#ifndef EFREET_BASE_H
2#define EFREET_BASE_H
3/**
4 * @file efreet_base.h
5 * @brief Contains the methods used to support the FDO base directory
6 * specification.
7 * @addtogroup Efreet_Base Efreet_Base: The XDG Base Directory Specification
8 * functions
9 * @ingroup Efreet
10 *
11 * @see http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
12 * @see http://0pointer.de/blog/projects/tmp.html
13 *
14 * @{
15 */
16
17
18/**
19 * @return Returns the XDG Data Home directory
20 * @brief Retrieves the XDG Data Home directory
21 *
22 * This is where user-specific data files should be written
23 * ($XDG_DATA_HOME or $HOME/.local/share).
24 */
25EAPI const char *efreet_data_home_get(void);
26
27/**
28 * @return Returns the Eina_List of preference ordered extra data directories
29 * @brief Returns the Eina_List of preference ordered extra data directories
30 *
31 * Ordered base directories relative to which data files should be
32 * searched ($XDG_DATA_DIRS or /usr/local/share/:/usr/share/)
33 *
34 * @note The returned list is static inside Efreet. If you add/remove from the
35 * list then the next call to efreet_data_dirs_get() will return your
36 * modified values. DO NOT free this list.
37 */
38EAPI Eina_List *efreet_data_dirs_get(void);
39
40
41/**
42 * @return Returns the XDG Config Home directory
43 * @brief Retrieves the XDG Config Home directory
44 *
45 * This is where user-specific configuration files should be
46 * written ($XDG_CONFIG_HOME or $HOME/.config).
47 */
48EAPI const char *efreet_config_home_get(void);
49
50/**
51 * @return Returns the XDG Desktop directory
52 * @brief Retrieves the XDG Desktop directory
53 *
54 * This is where user-specific desktop files should be located. It's
55 * localized (translated) to current user locale
56 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
57 *
58 * @since 1.3
59 */
60EAPI const char *efreet_desktop_dir_get(void);
61
62/**
63 * @return Returns the XDG Download directory
64 * @brief Retrieves the XDG Download directory
65 *
66 * This is where user-specific download files should be located. It's
67 * localized (translated) to current user locale
68 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
69 *
70 * It's meant for large download or in-progress downloads, it's
71 * private for the user but may be shared among different
72 * machines. It's not automatically cleaned up.
73 *
74 * @see efreet_cache_home_get()
75 * @see efreet_runtime_dir_get()
76 * @see http://0pointer.de/blog/projects/tmp.html
77 *
78 * @since 1.8
79 */
80EAPI const char *efreet_download_dir_get(void);
81
82/**
83 * @return Returns the XDG Templates directory
84 * @brief Retrieves the XDG Templates directory
85 *
86 * This is where user-specific template files should be located. It's
87 * localized (translated) to current user locale
88 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
89 *
90 * @see efreet_documents_dir_get()
91 * @see efreet_music_dir_get()
92 * @see efreet_pictures_dir_get()
93 * @see efreet_videos_dir_get()
94 *
95 * @since 1.8
96 */
97EAPI const char *efreet_templates_dir_get(void);
98
99/**
100 * @return Returns the XDG Public Share directory
101 * @brief Retrieves the XDG Public Share directory
102 *
103 * This is where user-specific public shareable files should be
104 * located. It's localized (translated) to current user locale
105 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
106 *
107 * Usually local file servers should look here (Apache, Samba, FTP).
108 *
109 * @since 1.8
110 */
111EAPI const char *efreet_public_share_dir_get(void);
112
113/**
114 * @return Returns the XDG Documents directory
115 * @brief Retrieves the XDG Documents directory
116 *
117 * This is where user-specific documents files should be located. It's
118 * localized (translated) to current user locale
119 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
120 *
121 * @see efreet_templates_dir_get()
122 * @see efreet_music_dir_get()
123 * @see efreet_pictures_dir_get()
124 * @see efreet_videos_dir_get()
125 *
126 * @since 1.8
127 */
128EAPI const char *efreet_documents_dir_get(void);
129
130/**
131 * @return Returns the XDG Music directory
132 * @brief Retrieves the XDG Music directory
133 *
134 * This is where user-specific music files should be located. It's
135 * localized (translated) to current user locale
136 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
137 *
138 * @see efreet_templates_dir_get()
139 * @see efreet_download_dir_get()
140 * @see efreet_pictures_dir_get()
141 * @see efreet_videos_dir_get()
142 *
143 * @since 1.8
144 */
145EAPI const char *efreet_music_dir_get(void);
146
147/**
148 * @return Returns the XDG Pictures directory
149 * @brief Retrieves the XDG Pictures directory
150 *
151 * This is where user-specific pictures files should be located. It's
152 * localized (translated) to current user locale
153 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
154 *
155 * @see efreet_templates_dir_get()
156 * @see efreet_documents_dir_get()
157 * @see efreet_music_dir_get()
158 * @see efreet_videos_dir_get()
159 *
160 * @since 1.8
161 */
162EAPI const char *efreet_pictures_dir_get(void);
163
164/**
165 * @return Returns the XDG Videos directory
166 * @brief Retrieves the XDG Videos directory
167 *
168 * This is where user-specific video files should be located. It's
169 * localized (translated) to current user locale
170 * (~/.config/user-dirs.locale and ~/.config/user-dirs.dirs).
171 *
172 * @see efreet_templates_dir_get()
173 * @see efreet_documents_dir_get()
174 * @see efreet_music_dir_get()
175 * @see efreet_pictures_dir_get()
176 *
177 * @since 1.8
178 */
179EAPI const char *efreet_videos_dir_get(void);
180
181/**
182 * @return Returns the Eina_List of preference ordered extra config directories
183 * @brief Returns the Eina_List of preference ordered extra config
184 * directories
185 *
186 * Ordered base directories relative to which configuration files
187 * should be searched ($XDG_CONFIG_DIRS or /etc/xdg)
188 *
189 * @note The returned list is static inside Efreet. If you add/remove from the
190 * list then the next call to efreet_config_dirs_get() will return your
191 * modified values. DO NOT free this list.
192 */
193EAPI Eina_List *efreet_config_dirs_get(void);
194
195
196/**
197 * @return Returns the XDG Cache Home directory
198 * @brief Retrieves the XDG Cache Home directory
199 *
200 * This is the base directory relative to which user specific
201 * non-essential data files should be stored ($XDG_CACHE_HOME or
202 * $HOME/.cache).
203 *
204 * @see efreet_runtime_dir_get()
205 * @see efreet_download_dir_get()
206 * @see efreet_config_home_get()
207 */
208EAPI const char *efreet_cache_home_get(void);
209
210/**
211 * @return Returns the XDG User Runtime directory.
212 * @brief Retrieves the XDG User Runtime directory.
213 *
214 * This is the base directory relative to which user-specific
215 * non-essential runtime files and other file objects (such as
216 * sockets, named pipes, ...) should be stored. The directory @b must
217 * be owned by the user, and he @b must be the only one having read
218 * and write access to it. Its Unix access mode @b must be 0700.
219 *
220 * The lifetime of this directory @b must be bound to the user being
221 * logged in. It @b must be created when the user first logs in and if
222 * the user fully logs out the directory @b must be removed. If the
223 * user logs in more than once he should get pointed to the same
224 * directory, and it is mandatory that the directory continues to
225 * exist from his first login to his last logout on the system, and
226 * not removed in between. Files in the directory @b must not survive
227 * reboot or a full logout/login cycle.
228 *
229 * The directory @b must be on a local file system and not shared with
230 * any other system. The directory @b must by fully-featured by the
231 * standards of the operating system. More specifically, on Unix-like
232 * operating systems AF_UNIX sockets, symbolic links, hard links,
233 * proper permissions, file locking, sparse files, memory mapping,
234 * file change notifications, a reliable hard link count must be
235 * supported, and no restrictions on the file name character set
236 * should be imposed. Files in this directory @b may be subjected to
237 * periodic clean-up. To ensure that your files are not removed, they
238 * should have their access time timestamp modified at least once
239 * every 6 hours of monotonic time or the 'sticky' bit should be set
240 * on the file.
241 *
242 * If @c NULL applications should fall back to a replacement directory
243 * with similar capabilities and print a warning message. Applications
244 * should use this directory for communication and synchronization
245 * purposes and should not place larger files in it, since it might
246 * reside in runtime memory and cannot necessarily be swapped out to
247 * disk.
248 *
249 * @note this directory is similar to @c /run and is often created in
250 * tmpfs (memory-only/RAM filesystem). It is created, managed and
251 * cleaned automatically by systemd.
252 *
253 * @since 1.8
254 */
255EAPI const char *efreet_runtime_dir_get(void);
256
257/**
258 * @return Returns the current hostname
259 * @brief Returns the current hostname or empty string if not found
260 */
261EAPI const char *efreet_hostname_get(void);
262
263/**
264 * Efreet_Event_Cache_Update
265 */
266typedef struct _Efreet_Event_Cache_Update Efreet_Event_Cache_Update;
267
268/**
269 * Efreet_Event_Cache_Update
270 * @brief event struct sent with EFREET_EVENT_*_CACHE_UPDATE
271 */
272struct _Efreet_Event_Cache_Update
273{
274 int error;
275};
276
277/**
278 * @}
279 */
280
281#endif
diff --git a/src/lib/efreet/efreet_cache.c b/src/lib/efreet/efreet_cache.c
new file mode 100644
index 0000000..6e99ee3
--- /dev/null
+++ b/src/lib/efreet/efreet_cache.c
@@ -0,0 +1,1181 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5/* TODO: Consider flushing local icons cache after idling.
6 * Icon requests will probably come in batches, f.ex. during menu
7 * browsing.
8 */
9
10#include <libgen.h>
11#include <unistd.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14
15#include <Eet.h>
16#include <Ecore.h>
17#include <Ecore_File.h>
18#include <EDBus.h>
19
20/* define macros and variable for using the eina logging system */
21#define EFREET_MODULE_LOG_DOM _efreet_cache_log_dom
22static int _efreet_cache_log_dom = -1;
23
24#include "Efreet.h"
25#include "efreet_private.h"
26#include "efreet_cache_private.h"
27
28#define NON_EXISTING (void *)-1
29
30typedef struct _Efreet_Old_Cache Efreet_Old_Cache;
31
32struct _Efreet_Old_Cache
33{
34 Eina_Hash *hash;
35 Eet_File *ef;
36};
37
38/* TODO: Common define location with daemon */
39#define BUS "org.enlightenment.Efreet"
40#define PATH "/org/enlightenment/Efreet"
41#define INTERFACE "org.enlightenment.Efreet"
42
43static EDBus_Connection *conn = NULL;
44static EDBus_Proxy *proxy = NULL;
45/**
46 * Data for cache files
47 */
48static Eet_Data_Descriptor *directory_edd = NULL;
49static Eet_Data_Descriptor *icon_theme_edd = NULL;
50static Eet_Data_Descriptor *icon_theme_directory_edd = NULL;
51
52static Eet_Data_Descriptor *icon_fallback_edd = NULL;
53static Eet_Data_Descriptor *icon_element_pointer_edd = NULL;
54static Eet_Data_Descriptor *icon_element_edd = NULL;
55static Eet_Data_Descriptor *icon_edd = NULL;
56
57static Eet_File *icon_cache = NULL;
58static Eet_File *fallback_cache = NULL;
59static Eet_File *icon_theme_cache = NULL;
60
61static Eina_Hash *themes = NULL;
62static Eina_Hash *icons = NULL;
63static Eina_Hash *fallbacks = NULL;
64
65static const char *icon_theme_cache_file = NULL;
66
67static const char *theme_name = NULL;
68
69static Eet_Data_Descriptor *version_edd = NULL;
70static Eet_Data_Descriptor *desktop_edd = NULL;
71static Eet_Data_Descriptor *hash_array_string_edd = NULL;
72static Eet_Data_Descriptor *array_string_edd = NULL;
73static Eet_Data_Descriptor *hash_string_edd = NULL;
74
75static Eina_Hash *desktops = NULL;
76static Eet_File *desktop_cache = NULL;
77static const char *desktop_cache_file = NULL;
78
79static Eina_List *old_desktop_caches = NULL;
80
81static const char *util_cache_file = NULL;
82static Eet_File *util_cache = NULL;
83static Efreet_Cache_Hash *util_cache_hash = NULL;
84static const char *util_cache_hash_key = NULL;
85static Efreet_Cache_Array_String *util_cache_names = NULL;
86static const char *util_cache_names_key = NULL;
87
88static void efreet_cache_edd_shutdown(void);
89static void efreet_cache_icon_free(Efreet_Cache_Icon *icon);
90static void efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon);
91static void efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme);
92
93static Eina_Bool efreet_cache_check(Eet_File **ef, const char *path, int major);
94static void *efreet_cache_close(Eet_File *ef);
95
96static void on_send_register(void *data, const EDBus_Message *msg, EDBus_Pending *pending);
97static void desktop_cache_update(void *context, const EDBus_Message *msg);
98static void icon_cache_update(void *context, const EDBus_Message *msg);
99
100static void icon_cache_update_free(void *data, void *ev);
101
102static void *hash_array_string_add(void *hash, const char *key, void *data);
103
104EAPI int EFREET_EVENT_ICON_CACHE_UPDATE = 0;
105EAPI int EFREET_EVENT_DESKTOP_CACHE_UPDATE = 0;
106EAPI int EFREET_EVENT_DESKTOP_CACHE_BUILD = 0;
107
108int
109efreet_cache_init(void)
110{
111 _efreet_cache_log_dom = eina_log_domain_register("efreet_cache", EFREET_DEFAULT_LOG_COLOR);
112 if (_efreet_cache_log_dom < 0)
113 return 0;
114
115 EFREET_EVENT_ICON_CACHE_UPDATE = ecore_event_type_new();
116 EFREET_EVENT_DESKTOP_CACHE_UPDATE = ecore_event_type_new();
117 EFREET_EVENT_DESKTOP_CACHE_BUILD = ecore_event_type_new();
118
119 themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
120 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
121 fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
122 desktops = eina_hash_string_superfast_new(NULL);
123
124 edbus_init();
125 if (efreet_cache_update)
126 {
127 EDBus_Object *obj;
128
129 conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
130 if (!conn) goto error;
131
132 obj = edbus_object_get(conn, BUS, PATH);
133 proxy = edbus_proxy_get(obj, INTERFACE);
134 edbus_proxy_signal_handler_add(proxy, "IconCacheUpdate", icon_cache_update, NULL);
135 edbus_proxy_signal_handler_add(proxy, "DesktopCacheUpdate", desktop_cache_update, NULL);
136
137 edbus_proxy_call(proxy, "Register", on_send_register, NULL, -1, "s", efreet_language_get());
138
139 /*
140 * TODO: Needed?
141 edbus_name_owner_changed_callback_add(conn, BUS, on_name_owner_changed,
142 conn, EINA_TRUE);
143 */
144 }
145
146 return 1;
147error:
148 if (themes) eina_hash_free(themes);
149 themes = NULL;
150 if (icons) eina_hash_free(icons);
151 icons = NULL;
152 if (fallbacks) eina_hash_free(fallbacks);
153 fallbacks = NULL;
154 if (desktops) eina_hash_free(desktops);
155 desktops = NULL;
156
157 efreet_cache_edd_shutdown();
158 return 0;
159}
160
161void
162efreet_cache_shutdown(void)
163{
164 Efreet_Old_Cache *d;
165
166 IF_RELEASE(theme_name);
167
168 icon_cache = efreet_cache_close(icon_cache);
169 icon_theme_cache = efreet_cache_close(icon_theme_cache);
170
171 IF_FREE_HASH(themes);
172 IF_FREE_HASH(icons);
173 IF_FREE_HASH(fallbacks);
174
175 IF_FREE_HASH_CB(desktops, EINA_FREE_CB(efreet_cache_desktop_free));
176 desktop_cache = efreet_cache_close(desktop_cache);
177 IF_RELEASE(desktop_cache_file);
178
179 efreet_cache_edd_shutdown();
180 IF_RELEASE(icon_theme_cache_file);
181
182 if (old_desktop_caches)
183 ERR("This application has not properly closed all its desktop references!");
184 EINA_LIST_FREE(old_desktop_caches, d)
185 {
186 eina_hash_free(d->hash);
187 eet_close(d->ef);
188 free(d);
189 }
190
191 IF_RELEASE(util_cache_names_key);
192 efreet_cache_array_string_free(util_cache_names);
193 util_cache_names = NULL;
194
195 IF_RELEASE(util_cache_hash_key);
196 if (util_cache_hash)
197 {
198 eina_hash_free(util_cache_hash->hash);
199 free(util_cache_hash);
200 util_cache_hash = NULL;
201 }
202
203 util_cache = efreet_cache_close(util_cache);
204 IF_RELEASE(util_cache_file);
205
206 eina_log_domain_unregister(_efreet_cache_log_dom);
207 _efreet_cache_log_dom = -1;
208
209 /*
210 * TODO: Needed??
211 edbus_name_owner_changed_callback_del(conn, BUS, on_name_owner_changed, conn);
212 */
213 if (conn)
214 {
215 EDBus_Object *obj = edbus_proxy_object_get(proxy);
216 edbus_proxy_unref(proxy);
217 edbus_object_unref(obj);
218 edbus_connection_unref(conn);
219 }
220
221 edbus_shutdown();
222}
223
224/*
225 * Needs EAPI because of helper binaries
226 */
227EAPI const char *
228efreet_icon_cache_file(const char *theme)
229{
230 static char cache_file[PATH_MAX] = { '\0' };
231 const char *cache;
232
233 EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL);
234
235 cache = efreet_cache_home_get();
236
237 snprintf(cache_file, sizeof(cache_file), "%s/efreet/icons_%s_%s.eet", cache, theme, efreet_hostname_get());
238
239 return cache_file;
240}
241
242/*
243 * Needs EAPI because of helper binaries
244 */
245EAPI const char *
246efreet_icon_theme_cache_file(void)
247{
248 char tmp[PATH_MAX] = { '\0' };
249
250 if (icon_theme_cache_file) return icon_theme_cache_file;
251
252 snprintf(tmp, sizeof(tmp), "%s/efreet/icon_themes_%s.eet",
253 efreet_cache_home_get(), efreet_hostname_get());
254 icon_theme_cache_file = eina_stringshare_add(tmp);
255
256 return icon_theme_cache_file;
257}
258
259/*
260 * Needs EAPI because of helper binaries
261 */
262EAPI const char *
263efreet_desktop_util_cache_file(void)
264{
265 char tmp[PATH_MAX] = { '\0' };
266 const char *cache_dir, *lang, *country, *modifier;
267
268 if (util_cache_file) return util_cache_file;
269
270 cache_dir = efreet_cache_home_get();
271 lang = efreet_lang_get();
272 country = efreet_lang_country_get();
273 modifier = efreet_lang_modifier_get();
274
275 if (lang && country && modifier)
276 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s@%s.eet", cache_dir, efreet_hostname_get(), lang, country, modifier);
277 else if (lang && country)
278 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s.eet", cache_dir, efreet_hostname_get(), lang, country);
279 else if (lang)
280 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s.eet", cache_dir, efreet_hostname_get(), lang);
281 else
282 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s.eet", cache_dir, efreet_hostname_get());
283
284 util_cache_file = eina_stringshare_add(tmp);
285 return util_cache_file;
286}
287
288/*
289 * Needs EAPI because of helper binaries
290 */
291EAPI Eet_Data_Descriptor *
292efreet_version_edd(void)
293{
294 Eet_Data_Descriptor_Class eddc;
295
296 if (version_edd) return version_edd;
297
298 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Version);
299 version_edd = eet_data_descriptor_file_new(&eddc);
300 if (!version_edd) return NULL;
301
302 EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
303 "minor", minor, EET_T_UCHAR);
304 EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version,
305 "major", major, EET_T_UCHAR);
306
307 return version_edd;
308}
309
310/*
311 * Needs EAPI because of helper binaries
312 */
313EAPI Eet_Data_Descriptor *
314efreet_hash_array_string_edd(void)
315{
316 Eet_Data_Descriptor_Class eddc;
317
318 if (hash_array_string_edd) return hash_array_string_edd;
319
320 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
321 eddc.func.hash_add = hash_array_string_add;
322 hash_array_string_edd = eet_data_descriptor_file_new(&eddc);
323 if (!hash_array_string_edd) return NULL;
324
325 EET_DATA_DESCRIPTOR_ADD_HASH(hash_array_string_edd, Efreet_Cache_Hash,
326 "hash", hash, efreet_array_string_edd());
327
328 return hash_array_string_edd;
329}
330
331/*
332 * Needs EAPI because of helper binaries
333 */
334EAPI Eet_Data_Descriptor *
335efreet_hash_string_edd(void)
336{
337 Eet_Data_Descriptor_Class eddc;
338
339 if (hash_string_edd) return hash_string_edd;
340
341 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash);
342 hash_string_edd = eet_data_descriptor_file_new(&eddc);
343 if (!hash_string_edd) return NULL;
344
345 EET_DATA_DESCRIPTOR_ADD_HASH_STRING(hash_string_edd, Efreet_Cache_Hash,
346 "hash", hash);
347
348 return hash_string_edd;
349}
350
351/*
352 * Needs EAPI because of helper binaries
353 */
354EAPI Eet_Data_Descriptor *
355efreet_array_string_edd(void)
356{
357 Eet_Data_Descriptor_Class eddc;
358
359 if (array_string_edd) return array_string_edd;
360
361 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Array_String);
362 array_string_edd = eet_data_descriptor_file_new(&eddc);
363 if (!array_string_edd) return NULL;
364 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(array_string_edd, Efreet_Cache_Array_String,
365 "array", array);
366
367 return array_string_edd;
368}
369
370/*
371 * Needs EAPI because of helper binaries
372 */
373EAPI const char *
374efreet_desktop_cache_file(void)
375{
376 char tmp[PATH_MAX] = { '\0' };
377 const char *cache, *lang, *country, *modifier;
378
379 if (desktop_cache_file) return desktop_cache_file;
380
381 cache = efreet_cache_home_get();
382 lang = efreet_lang_get();
383 country = efreet_lang_country_get();
384 modifier = efreet_lang_modifier_get();
385
386 if (lang && country && modifier)
387 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s@%s.eet", cache, efreet_hostname_get(), lang, country, modifier);
388 else if (lang && country)
389 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s.eet", cache, efreet_hostname_get(), lang, country);
390 else if (lang)
391 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s.eet", cache, efreet_hostname_get(), lang);
392 else
393 snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s.eet", cache, efreet_hostname_get());
394
395 desktop_cache_file = eina_stringshare_add(tmp);
396 return desktop_cache_file;
397}
398
399#define EDD_SHUTDOWN(Edd) \
400 if (Edd) eet_data_descriptor_free(Edd); \
401Edd = NULL;
402
403static void
404efreet_cache_edd_shutdown(void)
405{
406 EDD_SHUTDOWN(version_edd);
407 EDD_SHUTDOWN(desktop_edd);
408 EDD_SHUTDOWN(hash_array_string_edd);
409 EDD_SHUTDOWN(array_string_edd);
410 EDD_SHUTDOWN(hash_string_edd);
411 EDD_SHUTDOWN(icon_theme_edd);
412 EDD_SHUTDOWN(icon_theme_directory_edd);
413 EDD_SHUTDOWN(directory_edd);
414 EDD_SHUTDOWN(icon_fallback_edd);
415 EDD_SHUTDOWN(icon_element_pointer_edd);
416 EDD_SHUTDOWN(icon_element_edd);
417 EDD_SHUTDOWN(icon_edd);
418}
419
420#define EFREET_POINTER_TYPE(Edd_Dest, Edd_Source, Type) \
421{ \
422 typedef struct _Efreet_##Type##_Pointer Efreet_##Type##_Pointer; \
423 struct _Efreet_##Type##_Pointer \
424 { \
425 Efreet_##Type *pointer; \
426 }; \
427 \
428 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_##Type##_Pointer); \
429 Edd_Dest = eet_data_descriptor_file_new(&eddc); \
430 EET_DATA_DESCRIPTOR_ADD_SUB(Edd_Dest, Efreet_##Type##_Pointer, \
431 "pointer", pointer, Edd_Source); \
432}
433
434static Eet_Data_Descriptor *
435efreet_icon_directory_edd(void)
436{
437 Eet_Data_Descriptor_Class eddc;
438
439 if (directory_edd) return directory_edd;
440
441 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Directory);
442 directory_edd = eet_data_descriptor_file_new(&eddc);
443 if (!directory_edd) return NULL;
444
445 EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory,
446 "modified_time", modified_time, EET_T_LONG_LONG);
447
448 return directory_edd;
449}
450
451/*
452 * Needs EAPI because of helper binaries
453 */
454EAPI Eet_Data_Descriptor *
455efreet_icon_edd(void)
456{
457 Eet_Data_Descriptor_Class eddc;
458
459 if (icon_edd) return icon_edd;
460
461 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Element);
462 icon_element_edd = eet_data_descriptor_file_new(&eddc);
463 if (!icon_element_edd) return NULL;
464
465 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
466 "type", type, EET_T_USHORT);
467 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
468 "normal", normal, EET_T_USHORT);
469 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
470 "normal", normal, EET_T_USHORT);
471 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
472 "min", min, EET_T_USHORT);
473 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element,
474 "max", max, EET_T_USHORT);
475 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_element_edd, Efreet_Cache_Icon_Element,
476 "paths", paths);
477
478 EFREET_POINTER_TYPE(icon_element_pointer_edd, icon_element_edd, Cache_Icon_Element);
479
480 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon);
481 icon_edd = eet_data_descriptor_file_new(&eddc);
482 if (!icon_edd) return NULL;
483
484 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_edd, Efreet_Cache_Icon,
485 "theme", theme, EET_T_STRING);
486 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(icon_edd, Efreet_Cache_Icon,
487 "icons", icons, icon_element_pointer_edd);
488
489 return icon_edd;
490}
491
492/*
493 * Needs EAPI because of helper binaries
494 */
495EAPI Eet_Data_Descriptor *
496efreet_icon_theme_edd(Eina_Bool cache)
497{
498 Eet_Data_Descriptor_Class eddc;
499
500 if (icon_theme_edd) return icon_theme_edd;
501
502 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Icon_Theme_Directory);
503 icon_theme_directory_edd = eet_data_descriptor_file_new(&eddc);
504 if (!icon_theme_directory_edd) return NULL;
505
506 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
507 "name", name, EET_T_STRING);
508 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
509 "context", context, EET_T_UCHAR);
510 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
511 "type", type, EET_T_UCHAR);
512 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
513 "size.normal", size.normal, EET_T_UINT);
514 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
515 "size.min", size.min, EET_T_UINT);
516 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
517 "size.max", size.max, EET_T_UINT);
518 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory,
519 "size.threshold", size.threshold, EET_T_UINT);
520
521 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Theme);
522 icon_theme_edd = eet_data_descriptor_file_new(&eddc);
523 if (!icon_theme_edd) return NULL;
524
525 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
526 "name.internal", theme.name.internal, EET_T_STRING);
527 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
528 "name.name", theme.name.name, EET_T_STRING);
529 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
530 "comment", theme.comment, EET_T_STRING);
531 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
532 "example_icon", theme.example_icon, EET_T_STRING);
533
534 eet_data_descriptor_element_add(icon_theme_edd, "paths", EET_T_STRING, EET_G_LIST,
535 offsetof(Efreet_Cache_Icon_Theme, theme.paths), 0, NULL, NULL);
536 eet_data_descriptor_element_add(icon_theme_edd, "inherits", EET_T_STRING, EET_G_LIST,
537 offsetof(Efreet_Cache_Icon_Theme, theme.inherits), 0, NULL, NULL);
538 EET_DATA_DESCRIPTOR_ADD_LIST(icon_theme_edd, Efreet_Cache_Icon_Theme,
539 "directories", theme.directories, icon_theme_directory_edd);
540
541 if (cache)
542 {
543 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
544 "last_cache_check", last_cache_check, EET_T_LONG_LONG);
545
546 EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme,
547 "path", path, EET_T_STRING);
548
549 EET_DATA_DESCRIPTOR_ADD_HASH(icon_theme_edd, Efreet_Cache_Icon_Theme,
550 "dirs", dirs, efreet_icon_directory_edd());
551 }
552
553 return icon_theme_edd;
554}
555
556/*
557 * Needs EAPI because of helper binaries
558 */
559EAPI Eet_Data_Descriptor *
560efreet_icon_fallback_edd(void)
561{
562 Eet_Data_Descriptor_Class eddc;
563
564 if (icon_fallback_edd) return icon_fallback_edd;
565
566 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Fallback_Icon);
567 icon_fallback_edd = eet_data_descriptor_file_new(&eddc);
568 if (!icon_fallback_edd) return NULL;
569
570 EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_fallback_edd,
571 Efreet_Cache_Fallback_Icon, "icons", icons);
572
573 return icon_fallback_edd;
574}
575
576/*
577 * Needs EAPI because of helper binaries
578 */
579EAPI Eet_Data_Descriptor *
580efreet_desktop_edd(void)
581{
582 Eet_Data_Descriptor_Class eddc;
583
584 if (desktop_edd) return desktop_edd;
585
586 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Desktop);
587 desktop_edd = eet_data_descriptor_file_new(&eddc);
588 if (!desktop_edd) return NULL;
589
590 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "type", desktop.type, EET_T_INT);
591 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "version", desktop.version, EET_T_STRING);
592 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "orig_path", desktop.orig_path, EET_T_STRING);
593 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "load_time", desktop.load_time, EET_T_LONG_LONG);
594 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "name", desktop.name, EET_T_STRING);
595 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "generic_name", desktop.generic_name, EET_T_STRING);
596 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "comment", desktop.comment, EET_T_STRING);
597 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "icon", desktop.icon, EET_T_STRING);
598 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "try_exec", desktop.try_exec, EET_T_STRING);
599 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "exec", desktop.exec, EET_T_STRING);
600 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "path", desktop.path, EET_T_STRING);
601 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_wm_class", desktop.startup_wm_class, EET_T_STRING);
602 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "url", desktop.url, EET_T_STRING);
603 eet_data_descriptor_element_add(desktop_edd, "only_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.only_show_in), 0, NULL, NULL);
604 eet_data_descriptor_element_add(desktop_edd, "not_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.not_show_in), 0, NULL, NULL);
605 eet_data_descriptor_element_add(desktop_edd, "categories", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.categories), 0, NULL, NULL);
606 eet_data_descriptor_element_add(desktop_edd, "mime_types", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.mime_types), 0, NULL, NULL);
607 eet_data_descriptor_element_add(desktop_edd, "x", EET_T_STRING, EET_G_HASH, offsetof(Efreet_Cache_Desktop, desktop.x), 0, NULL, NULL);
608 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "no_display", desktop.no_display, EET_T_UCHAR);
609 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "hidden", desktop.hidden, EET_T_UCHAR);
610 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "terminal", desktop.terminal, EET_T_UCHAR);
611 EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_notify", desktop.startup_notify, EET_T_UCHAR);
612
613 return desktop_edd;
614}
615
616Efreet_Cache_Icon *
617efreet_cache_icon_find(Efreet_Icon_Theme *theme, const char *icon)
618{
619 Efreet_Cache_Icon *cache = NULL;
620
621 if (theme_name && strcmp(theme_name, theme->name.internal))
622 {
623 /* FIXME: this is bad if people have pointer to this cache, things will go wrong */
624 INF("theme_name change from `%s` to `%s`", theme_name, theme->name.internal);
625 IF_RELEASE(theme_name);
626 icon_cache = efreet_cache_close(icon_cache);
627 eina_hash_free(icons);
628 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
629 }
630
631 if (!efreet_cache_check(&icon_cache, efreet_icon_cache_file(theme->name.internal), EFREET_ICON_CACHE_MAJOR)) return NULL;
632 if (!theme_name)
633 theme_name = eina_stringshare_add(theme->name.internal);
634
635 cache = eina_hash_find(icons, icon);
636 if (cache == NON_EXISTING) return NULL;
637 if (cache) return cache;
638
639 cache = eet_data_read(icon_cache, efreet_icon_edd(), icon);
640 if (cache)
641 eina_hash_add(icons, icon, cache);
642 else
643 eina_hash_add(icons, icon, NON_EXISTING);
644 return cache;
645}
646
647Efreet_Cache_Fallback_Icon *
648efreet_cache_icon_fallback_find(const char *icon)
649{
650 Efreet_Cache_Fallback_Icon *cache;
651
652 if (!efreet_cache_check(&fallback_cache, efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EFREET_ICON_CACHE_MAJOR)) return NULL;
653
654 cache = eina_hash_find(fallbacks, icon);
655 if (cache == NON_EXISTING) return NULL;
656 if (cache) return cache;
657
658 cache = eet_data_read(fallback_cache, efreet_icon_fallback_edd(), icon);
659 if (cache)
660 eina_hash_add(fallbacks, icon, cache);
661 else
662 eina_hash_add(fallbacks, icon, NON_EXISTING);
663 return cache;
664}
665
666Efreet_Icon_Theme *
667efreet_cache_icon_theme_find(const char *theme)
668{
669 Efreet_Cache_Icon_Theme *cache;
670
671 if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
672
673 cache = eina_hash_find(themes, theme);
674 if (cache == NON_EXISTING) return NULL;
675 if (cache) return &(cache->theme);
676
677 cache = eet_data_read(icon_theme_cache, efreet_icon_theme_edd(EINA_FALSE), theme);
678 if (cache)
679 {
680 eina_hash_add(themes, theme, cache);
681 return &(cache->theme);
682 }
683 else
684 eina_hash_add(themes, theme, NON_EXISTING);
685 return NULL;
686}
687
688static void
689efreet_cache_icon_free(Efreet_Cache_Icon *icon)
690{
691 unsigned int i;
692
693 if (!icon) return;
694 if (icon == NON_EXISTING) return;
695
696 for (i = 0; i < icon->icons_count; ++i)
697 {
698 free(icon->icons[i]->paths);
699 free(icon->icons[i]);
700 }
701
702 free(icon->icons);
703 free(icon);
704}
705
706static void
707efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon)
708{
709 if (!icon) return;
710 if (icon == NON_EXISTING) return;
711
712 free(icon->icons);
713 free(icon);
714}
715
716static void
717efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme)
718{
719 void *data;
720
721 if (!theme) return;
722 if (theme == NON_EXISTING) return;
723
724 eina_list_free(theme->paths);
725 eina_list_free(theme->inherits);
726 EINA_LIST_FREE(theme->directories, data)
727 free(data);
728
729 free(theme);
730}
731
732Eina_List *
733efreet_cache_icon_theme_list(void)
734{
735 Eina_List *ret = NULL;
736 char **keys;
737 int i, num;
738
739 if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL;
740 keys = eet_list(icon_theme_cache, "*", &num);
741 for (i = 0; i < num; i++)
742 {
743 Efreet_Icon_Theme *theme;
744 if (!strncmp(keys[i], "__efreet", 8)) continue;
745
746 theme = eina_hash_find(themes, keys[i]);
747 if (!theme)
748 theme = efreet_cache_icon_theme_find(keys[i]);
749 if (theme && theme != NON_EXISTING)
750 ret = eina_list_append(ret, theme);
751 }
752 free(keys);
753 return ret;
754}
755
756/*
757 * Needs EAPI because of helper binaries
758 */
759EAPI void
760efreet_cache_array_string_free(Efreet_Cache_Array_String *array)
761{
762 if (!array) return;
763 free(array->array);
764 free(array);
765}
766
767Efreet_Desktop *
768efreet_cache_desktop_find(const char *file)
769{
770 Efreet_Cache_Desktop *cache;
771
772 if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) return NULL;
773
774 cache = eina_hash_find(desktops, file);
775 if (cache == NON_EXISTING) return NULL;
776 if (cache)
777 {
778 /* If less than one second since last stat, return desktop */
779 if ((ecore_time_get() - cache->check_time) < 1)
780 {
781 INF("Return without stat %f %f", ecore_time_get(), cache->check_time);
782 return &cache->desktop;
783 }
784 if (cache->desktop.load_time == ecore_file_mod_time(cache->desktop.orig_path))
785 {
786 INF("Return with stat %f %f", ecore_time_get(), cache->check_time);
787 cache->check_time = ecore_time_get();
788 return &cache->desktop;
789 }
790
791 /* We got stale data. The desktop will be free'd eventually as
792 * users will call efreet_desktop_free */
793 eina_hash_set(desktops, file, NON_EXISTING);
794 cache = NULL;
795 }
796
797 cache = eet_data_read(desktop_cache, efreet_desktop_edd(), file);
798 if (cache)
799 {
800 if (cache->desktop.load_time != ecore_file_mod_time(cache->desktop.orig_path))
801 {
802 /* Don't return stale data */
803 INF("We got stale data in the desktop cache");
804 efreet_cache_desktop_free(&cache->desktop);
805 eina_hash_set(desktops, file, NON_EXISTING);
806 }
807 else
808 {
809 cache->desktop.eet = 1;
810 cache->check_time = ecore_time_get();
811 eina_hash_set(desktops, cache->desktop.orig_path, cache);
812 return &cache->desktop;
813 }
814 }
815 else
816 eina_hash_set(desktops, file, NON_EXISTING);
817 return NULL;
818}
819
820void
821efreet_cache_desktop_free(Efreet_Desktop *desktop)
822{
823 Efreet_Old_Cache *d;
824 Efreet_Desktop *curr;
825 Eina_List *l;
826
827 if (!desktop ||
828 desktop == NON_EXISTING ||
829 !desktop->eet) return;
830
831 curr = eina_hash_find(desktops, desktop->orig_path);
832 if (curr == desktop)
833 {
834 INF("Found in current cache, purge\n");
835 eina_hash_del_by_key(desktops, desktop->orig_path);
836 }
837
838 EINA_LIST_FOREACH(old_desktop_caches, l, d)
839 {
840 curr = eina_hash_find(d->hash, desktop->orig_path);
841 if (curr == desktop)
842 {
843 INF("Found in old cache, purge\n");
844 eina_hash_del_by_key(d->hash, desktop->orig_path);
845 if (eina_hash_population(d->hash) == 0)
846 {
847 INF("Cache empty, close file\n");
848 eina_hash_free(d->hash);
849 eet_close(d->ef);
850 free(d);
851 old_desktop_caches = eina_list_remove_list(old_desktop_caches, l);
852 }
853 break;
854 }
855 }
856
857 eina_list_free(desktop->only_show_in);
858 eina_list_free(desktop->not_show_in);
859 eina_list_free(desktop->categories);
860 eina_list_free(desktop->mime_types);
861 IF_FREE_HASH(desktop->x);
862 free(desktop);
863}
864
865void
866efreet_cache_desktop_add(Efreet_Desktop *desktop)
867{
868 EDBus_Message *msg;
869 EDBus_Message_Iter *iter, *array_of_string;
870 char *path;
871
872 if (!efreet_cache_update) return;
873 /* TODO: Chunk updates */
874 path = ecore_file_dir_get(desktop->orig_path);
875 msg = edbus_proxy_method_call_new(proxy, "AddDesktopDirs");
876 iter = edbus_message_iter_get(msg);
877 array_of_string = edbus_message_iter_container_new(iter, 'a',"s");
878 edbus_message_iter_basic_append(array_of_string, 's', path);
879 edbus_message_iter_container_close(iter, array_of_string);
880 edbus_proxy_send(proxy, msg, NULL, NULL, -1);
881 edbus_message_unref(msg);
882 free(path);
883}
884
885void
886efreet_cache_icon_exts_add(Eina_List *exts)
887{
888 EDBus_Message *msg;
889 EDBus_Message_Iter *iter, *array_of_string;
890 Eina_List *l;
891 const char *ext;
892
893 if (!efreet_cache_update) return;
894 msg = edbus_proxy_method_call_new(proxy, "AddIconExts");
895 iter = edbus_message_iter_get(msg);
896 array_of_string = edbus_message_iter_container_new(iter, 'a',"s");
897 EINA_LIST_FOREACH(exts, l, ext)
898 edbus_message_iter_basic_append(array_of_string, 's', ext);
899 edbus_message_iter_container_close(iter, array_of_string);
900 edbus_proxy_send(proxy, msg, NULL, NULL, -1);
901 edbus_message_unref(msg);
902}
903
904void
905efreet_cache_icon_dirs_add(Eina_List *dirs)
906{
907 EDBus_Message *msg;
908 EDBus_Message_Iter *iter, *array_of_string;
909 Eina_List *l;
910 const char *dir;
911
912 if (!efreet_cache_update) return;
913 msg = edbus_proxy_method_call_new(proxy, "AddIconDirs");
914 iter = edbus_message_iter_get(msg);
915 array_of_string = edbus_message_iter_container_new(iter, 'a',"s");
916 EINA_LIST_FOREACH(dirs, l, dir)
917 edbus_message_iter_basic_append(array_of_string, 's', dir);
918 edbus_message_iter_container_close(iter, array_of_string);
919 edbus_proxy_send(proxy, msg, NULL, NULL, -1);
920 edbus_message_unref(msg);
921}
922
923void
924efreet_cache_desktop_close(void)
925{
926 IF_RELEASE(util_cache_names_key);
927 IF_RELEASE(util_cache_hash_key);
928
929 if ((desktop_cache) && (desktop_cache != NON_EXISTING))
930 {
931 Efreet_Old_Cache *d = NEW(Efreet_Old_Cache, 1);
932 if (d)
933 {
934 d->hash = desktops;
935 d->ef = desktop_cache;
936 old_desktop_caches = eina_list_append(old_desktop_caches, d);
937 }
938
939 desktops = eina_hash_string_superfast_new(NULL);
940 }
941 desktop_cache = NULL;
942
943 efreet_cache_array_string_free(util_cache_names);
944 util_cache_names = NULL;
945
946 if (util_cache_hash)
947 {
948 eina_hash_free(util_cache_hash->hash);
949 free(util_cache_hash);
950 util_cache_hash = NULL;
951 }
952
953 util_cache = efreet_cache_close(util_cache);
954
955 IF_RELEASE(desktop_cache_file);
956 IF_RELEASE(util_cache_file);
957}
958
959void
960efreet_cache_desktop_build(void)
961{
962 if (!efreet_cache_update) return;
963 if (proxy)
964 edbus_proxy_call(proxy, "BuildDesktopCache", NULL, NULL, -1, "s", efreet_language_get());
965}
966
967static Eina_Bool
968efreet_cache_check(Eet_File **ef, const char *path, int major)
969{
970 Efreet_Cache_Version *version;
971
972 if (*ef == NON_EXISTING) return EINA_FALSE;
973 if (*ef) return EINA_TRUE;
974 if (!*ef)
975 *ef = eet_open(path, EET_FILE_MODE_READ);
976 if (!*ef)
977 {
978 *ef = NON_EXISTING;
979 return EINA_FALSE;
980 }
981
982 version = eet_data_read(*ef, efreet_version_edd(), EFREET_CACHE_VERSION);
983 if ((!version) || (version->major != major))
984 {
985 IF_FREE(version);
986 eet_close(*ef);
987 *ef = NON_EXISTING;
988 return EINA_FALSE;
989 }
990 free(version);
991 return EINA_TRUE;
992}
993
994static void *
995efreet_cache_close(Eet_File *ef)
996{
997 if (ef && ef != NON_EXISTING)
998 eet_close(ef);
999 return NULL;
1000}
1001
1002Efreet_Cache_Hash *
1003efreet_cache_util_hash_string(const char *key)
1004{
1005 if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
1006 return util_cache_hash;
1007 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1008
1009 if (util_cache_hash)
1010 {
1011 /* free previous util_cache */
1012 IF_RELEASE(util_cache_hash_key);
1013 eina_hash_free(util_cache_hash->hash);
1014 free(util_cache_hash);
1015 }
1016 util_cache_hash_key = eina_stringshare_add(key);
1017 util_cache_hash = eet_data_read(util_cache, efreet_hash_string_edd(), key);
1018 return util_cache_hash;
1019}
1020
1021Efreet_Cache_Hash *
1022efreet_cache_util_hash_array_string(const char *key)
1023{
1024 if (util_cache_hash_key && !strcmp(key, util_cache_hash_key))
1025 return util_cache_hash;
1026 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1027
1028 IF_RELEASE(util_cache_hash_key);
1029 if (util_cache_hash)
1030 {
1031 /* free previous cache */
1032 eina_hash_free(util_cache_hash->hash);
1033 free(util_cache_hash);
1034 }
1035 util_cache_hash_key = eina_stringshare_add(key);
1036 util_cache_hash = eet_data_read(util_cache, efreet_hash_array_string_edd(), key);
1037 return util_cache_hash;
1038}
1039
1040Efreet_Cache_Array_String *
1041efreet_cache_util_names(const char *key)
1042{
1043 if (util_cache_names_key && !strcmp(key, util_cache_names_key))
1044 return util_cache_names;
1045 if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL;
1046
1047 if (util_cache_names)
1048 {
1049 /* free previous util_cache */
1050 IF_RELEASE(util_cache_names_key);
1051 efreet_cache_array_string_free(util_cache_names);
1052 }
1053 util_cache_names_key = eina_stringshare_add(key);
1054 util_cache_names = eet_data_read(util_cache, efreet_array_string_edd(), key);
1055 return util_cache_names;
1056}
1057
1058static void
1059on_send_register(void *data EINA_UNUSED, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED)
1060{
1061 const char *errname, *errmsg;
1062 Eina_Bool exists;
1063
1064 if (edbus_message_error_get(msg, &errname, &errmsg))
1065 {
1066 Efreet_Event_Cache_Update *ev = NULL;
1067
1068 ERR("%s %s", errname, errmsg);
1069
1070 ev = NEW(Efreet_Event_Cache_Update, 1);
1071 if (ev)
1072 {
1073 ev->error = 1;
1074 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, ev, NULL, NULL);
1075 }
1076 }
1077 else if (edbus_message_arguments_get(msg, "b", &exists) && exists)
1078 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, NULL, NULL, NULL);
1079}
1080
1081static void
1082desktop_cache_update(void *context EINA_UNUSED, const EDBus_Message *msg)
1083{
1084 Eina_Bool update;
1085
1086 if (edbus_message_arguments_get(msg, "b", &update))
1087 {
1088 if (update)
1089 {
1090 Efreet_Event_Cache_Update *ev = NULL;
1091
1092 efreet_cache_desktop_close();
1093
1094 ev = NEW(Efreet_Event_Cache_Update, 1);
1095 if (ev)
1096 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE, ev, NULL, NULL);
1097 }
1098 ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, NULL, NULL, NULL);
1099 }
1100}
1101
1102static void
1103icon_cache_update(void *context EINA_UNUSED, const EDBus_Message *msg)
1104{
1105 Efreet_Event_Cache_Update *ev = NULL;
1106 Efreet_Old_Cache *d = NULL;
1107 Eina_List *l = NULL;
1108 Eina_Bool update;
1109
1110 if (edbus_message_arguments_get(msg, "b", &update) && update)
1111 {
1112 ev = NEW(Efreet_Event_Cache_Update, 1);
1113 if (!ev) goto error;
1114
1115 IF_RELEASE(theme_name);
1116
1117 /* Save all old caches */
1118 d = NEW(Efreet_Old_Cache, 1);
1119 if (!d) goto error;
1120 d->hash = themes;
1121 d->ef = icon_theme_cache;
1122 l = eina_list_append(l, d);
1123
1124 d = NEW(Efreet_Old_Cache, 1);
1125 if (!d) goto error;
1126 d->hash = icons;
1127 d->ef = icon_cache;
1128 l = eina_list_append(l, d);
1129
1130 d = NEW(Efreet_Old_Cache, 1);
1131 if (!d) goto error;
1132 d->hash = fallbacks;
1133 d->ef = fallback_cache;
1134 l = eina_list_append(l, d);
1135
1136 /* Create new empty caches */
1137 themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free));
1138 icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free));
1139 fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free));
1140
1141 icon_theme_cache = NULL;
1142 icon_cache = NULL;
1143 fallback_cache = NULL;
1144
1145 /* Send event */
1146 ecore_event_add(EFREET_EVENT_ICON_CACHE_UPDATE, ev, icon_cache_update_free, l);
1147 }
1148 return;
1149error:
1150 IF_FREE(ev);
1151 EINA_LIST_FREE(l, d)
1152 free(d);
1153}
1154
1155static void
1156icon_cache_update_free(void *data, void *ev)
1157{
1158 Efreet_Old_Cache *d;
1159 Eina_List *l;
1160
1161 l = data;
1162 EINA_LIST_FREE(l, d)
1163 {
1164 if (d->hash)
1165 eina_hash_free(d->hash);
1166 efreet_cache_close(d->ef);
1167 free(d);
1168 }
1169 free(ev);
1170}
1171
1172static void *
1173hash_array_string_add(void *hash, const char *key, void *data)
1174{
1175 if (!hash)
1176 hash = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free));
1177 if (!hash)
1178 return NULL;
1179 eina_hash_add(hash, key, data);
1180 return hash;
1181}
diff --git a/src/lib/efreet/efreet_cache_private.h b/src/lib/efreet/efreet_cache_private.h
new file mode 100644
index 0000000..9729215
--- /dev/null
+++ b/src/lib/efreet/efreet_cache_private.h
@@ -0,0 +1,60 @@
1#ifndef EFREET_CACHE_PRIVATE_H
2#define EFREET_CACHE_PRIVATE_H
3
4#define EFREET_DESKTOP_CACHE_MAJOR 1
5#define EFREET_DESKTOP_CACHE_MINOR 0
6#define EFREET_DESKTOP_UTILS_CACHE_MAJOR 1
7#define EFREET_DESKTOP_UTILS_CACHE_MINOR 0
8
9#define EFREET_ICON_CACHE_MAJOR 1
10#define EFREET_ICON_CACHE_MINOR 0
11
12#define EFREET_CACHE_VERSION "__efreet//version"
13#define EFREET_CACHE_ICON_FALLBACK "__efreet_fallback"
14
15EAPI const char *efreet_desktop_util_cache_file(void);
16EAPI const char *efreet_desktop_cache_file(void);
17EAPI const char *efreet_icon_cache_file(const char *theme);
18EAPI const char *efreet_icon_theme_cache_file(void);
19
20EAPI Eet_Data_Descriptor *efreet_version_edd(void);
21EAPI Eet_Data_Descriptor *efreet_desktop_edd(void);
22EAPI Eet_Data_Descriptor *efreet_hash_array_string_edd(void);
23EAPI Eet_Data_Descriptor *efreet_hash_string_edd(void);
24EAPI Eet_Data_Descriptor *efreet_array_string_edd(void);
25EAPI Eet_Data_Descriptor *efreet_icon_theme_edd(Eina_Bool cache);
26EAPI Eet_Data_Descriptor *efreet_icon_edd(void);
27EAPI Eet_Data_Descriptor *efreet_icon_fallback_edd(void);
28
29typedef struct _Efreet_Cache_Icon_Theme Efreet_Cache_Icon_Theme;
30typedef struct _Efreet_Cache_Directory Efreet_Cache_Directory;
31typedef struct _Efreet_Cache_Desktop Efreet_Cache_Desktop;
32
33struct _Efreet_Cache_Icon_Theme
34{
35 Efreet_Icon_Theme theme;
36
37 long long last_cache_check; /**< Last time the cache was checked */
38
39 Eina_Hash *dirs; /**< All possible icon paths for this theme */
40
41 const char *path; /**< path to index.theme */
42
43 Eina_Bool hidden:1; /**< Should this theme be hidden from users */
44 Eina_Bool valid:1; /**< Have we seen an index for this theme */
45 Eina_Bool changed:1; /**< Changed since last seen */
46};
47
48struct _Efreet_Cache_Directory
49{
50 long long modified_time;
51};
52
53struct _Efreet_Cache_Desktop
54{
55 Efreet_Desktop desktop;
56
57 double check_time; /**< Last time we check for disk modification */
58};
59
60#endif
diff --git a/src/lib/efreet/efreet_copy.h b/src/lib/efreet/efreet_copy.h
new file mode 100644
index 0000000..ccffa00
--- /dev/null
+++ b/src/lib/efreet/efreet_copy.h
@@ -0,0 +1,10 @@
1#ifndef __EFREET_COPY_H
2#define __EFREET_COPY_H
3
4/* functions copied from lib to reduce include size */
5
6const char *efreet_icon_deprecated_user_dir_get(void);
7const char *efreet_icon_user_dir_get(void);
8
9#endif
10
diff --git a/src/lib/efreet/efreet_desktop.c b/src/lib/efreet/efreet_desktop.c
new file mode 100644
index 0000000..df932c0
--- /dev/null
+++ b/src/lib/efreet/efreet_desktop.c
@@ -0,0 +1,967 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "efreet_alloca.h"
6
7#ifdef HAVE_EVIL
8# include <Evil.h>
9#endif
10
11#include <Ecore_File.h>
12
13/* define macros and variable for using the eina logging system */
14#define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom
15int _efreet_desktop_log_dom = -1;
16
17#include "Efreet.h"
18#include "efreet_private.h"
19
20#define DESKTOP_VERSION "1.0"
21
22/**
23 * The current desktop environment (e.g. "Enlightenment" or "Gnome")
24 */
25static const char *desktop_environment = NULL;
26
27/**
28 * A list of the desktop types available
29 */
30static Eina_List *efreet_desktop_types = NULL;
31
32EAPI int EFREET_DESKTOP_TYPE_APPLICATION = 0;
33EAPI int EFREET_DESKTOP_TYPE_LINK = 0;
34EAPI int EFREET_DESKTOP_TYPE_DIRECTORY = 0;
35
36/**
37 * @internal
38 * Information about custom types
39 */
40typedef struct Efreet_Desktop_Type_Info Efreet_Desktop_Type_Info;
41struct Efreet_Desktop_Type_Info
42{
43 int id;
44 const char *type;
45 Efreet_Desktop_Type_Parse_Cb parse_func;
46 Efreet_Desktop_Type_Save_Cb save_func;
47 Efreet_Desktop_Type_Free_Cb free_func;
48};
49
50static int efreet_desktop_read(Efreet_Desktop *desktop);
51static Efreet_Desktop_Type_Info *efreet_desktop_type_parse(const char *type_str);
52static void efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info);
53static void *efreet_desktop_application_fields_parse(Efreet_Desktop *desktop,
54 Efreet_Ini *ini);
55static void efreet_desktop_application_fields_save(Efreet_Desktop *desktop,
56 Efreet_Ini *ini);
57static void *efreet_desktop_link_fields_parse(Efreet_Desktop *desktop,
58 Efreet_Ini *ini);
59static void efreet_desktop_link_fields_save(Efreet_Desktop *desktop,
60 Efreet_Ini *ini);
61static int efreet_desktop_generic_fields_parse(Efreet_Desktop *desktop,
62 Efreet_Ini *ini);
63static void efreet_desktop_generic_fields_save(Efreet_Desktop *desktop,
64 Efreet_Ini *ini);
65static Eina_Bool efreet_desktop_x_fields_parse(const Eina_Hash *hash,
66 const void *key,
67 void *data,
68 void *fdata);
69static Eina_Bool efreet_desktop_x_fields_save(const Eina_Hash *hash,
70 const void *key,
71 void *value,
72 void *fdata);
73static int efreet_desktop_environment_check(Efreet_Desktop *desktop);
74
75/**
76 * @internal
77 * @return Returns > 0 on success or 0 on failure
78 * @brief Initialize the Desktop parser subsystem
79 */
80int
81efreet_desktop_init(void)
82{
83 _efreet_desktop_log_dom = eina_log_domain_register
84 ("efreet_desktop", EFREET_DEFAULT_LOG_COLOR);
85 if (_efreet_desktop_log_dom < 0)
86 {
87 EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_desktop");
88 return 0;
89 }
90
91#ifdef HAVE_EVIL
92 if (!evil_sockets_init())
93 {
94 ERR("Could not initialize Winsock system");
95 return 0;
96 }
97#endif
98
99 efreet_desktop_types = NULL;
100
101 EFREET_DESKTOP_TYPE_APPLICATION = efreet_desktop_type_add("Application",
102 efreet_desktop_application_fields_parse,
103 efreet_desktop_application_fields_save,
104 NULL);
105 EFREET_DESKTOP_TYPE_LINK = efreet_desktop_type_add("Link",
106 efreet_desktop_link_fields_parse,
107 efreet_desktop_link_fields_save, NULL);
108 EFREET_DESKTOP_TYPE_DIRECTORY = efreet_desktop_type_add("Directory", NULL,
109 NULL, NULL);
110
111 return 1;
112}
113
114/**
115 * @internal
116 * @returns the number of initializations left for this system
117 * @brief Attempts to shut down the subsystem if nothing else is using it
118 */
119void
120efreet_desktop_shutdown(void)
121{
122 Efreet_Desktop_Type_Info *info;
123
124 IF_RELEASE(desktop_environment);
125 EINA_LIST_FREE(efreet_desktop_types, info)
126 efreet_desktop_type_info_free(info);
127#ifdef HAVE_EVIL
128 evil_sockets_shutdown();
129#endif
130 eina_log_domain_unregister(_efreet_desktop_log_dom);
131 _efreet_desktop_log_dom = -1;
132}
133
134EAPI Efreet_Desktop *
135efreet_desktop_get(const char *file)
136{
137 Efreet_Desktop *desktop;
138
139 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
140
141 desktop = efreet_desktop_new(file);
142 if (!desktop) return NULL;
143
144 /* If we didn't find this file in the eet cache, add path to search path */
145 if (!desktop->eet)
146 {
147 /* Check whether the desktop type is a system type,
148 * and therefor known by the cache builder */
149 Efreet_Desktop_Type_Info *info;
150
151 info = eina_list_nth(efreet_desktop_types, desktop->type);
152 if (info && (
153 info->id == EFREET_DESKTOP_TYPE_APPLICATION ||
154 info->id == EFREET_DESKTOP_TYPE_LINK ||
155 info->id == EFREET_DESKTOP_TYPE_DIRECTORY
156 ))
157 efreet_cache_desktop_add(desktop);
158 }
159
160 return desktop;
161}
162
163EAPI int
164efreet_desktop_ref(Efreet_Desktop *desktop)
165{
166 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
167 desktop->ref++;
168 return desktop->ref;
169}
170
171EAPI Efreet_Desktop *
172efreet_desktop_empty_new(const char *file)
173{
174 Efreet_Desktop *desktop;
175
176 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
177
178 desktop = NEW(Efreet_Desktop, 1);
179 if (!desktop) return NULL;
180
181 desktop->orig_path = strdup(file);
182 desktop->load_time = ecore_file_mod_time(file);
183
184 desktop->ref = 1;
185
186 return desktop;
187}
188
189EAPI Efreet_Desktop *
190efreet_desktop_new(const char *file)
191{
192 Efreet_Desktop *desktop = NULL;
193 char *tmp;
194
195 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
196
197 tmp = eina_file_path_sanitize(file);
198 if (!tmp) return NULL;
199
200 desktop = efreet_cache_desktop_find(tmp);
201 free(tmp);
202 if (desktop)
203 {
204 desktop->ref++;
205 if (!efreet_desktop_environment_check(desktop))
206 {
207 efreet_desktop_free(desktop);
208 return NULL;
209 }
210 return desktop;
211 }
212 return efreet_desktop_uncached_new(file);
213}
214
215EAPI Efreet_Desktop *
216efreet_desktop_uncached_new(const char *file)
217{
218 Efreet_Desktop *desktop = NULL;
219 char *tmp;
220
221 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
222 if (!ecore_file_exists(file)) return NULL;
223
224 tmp = eina_file_path_sanitize(file);
225 if (!tmp) return NULL;
226
227 desktop = NEW(Efreet_Desktop, 1);
228 if (!desktop)
229 {
230 free(tmp);
231 return NULL;
232 }
233 desktop->orig_path = tmp;
234 desktop->ref = 1;
235 if (!efreet_desktop_read(desktop))
236 {
237 efreet_desktop_free(desktop);
238 return NULL;
239 }
240
241 return desktop;
242}
243
244EAPI int
245efreet_desktop_save(Efreet_Desktop *desktop)
246{
247 Efreet_Desktop_Type_Info *info;
248 Efreet_Ini *ini;
249 int ok = 1;
250
251 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
252
253 ini = efreet_ini_new(NULL);
254 if (!ini) return 0;
255 efreet_ini_section_add(ini, "Desktop Entry");
256 efreet_ini_section_set(ini, "Desktop Entry");
257
258 info = eina_list_nth(efreet_desktop_types, desktop->type);
259 if (info)
260 {
261 efreet_ini_string_set(ini, "Type", info->type);
262 if (info->save_func) info->save_func(desktop, ini);
263 }
264 else
265 ok = 0;
266
267 if (ok)
268 {
269 char *val;
270
271 if (desktop->only_show_in)
272 {
273 val = efreet_desktop_string_list_join(desktop->only_show_in);
274 if (val)
275 {
276 efreet_ini_string_set(ini, "OnlyShowIn", val);
277 FREE(val);
278 }
279 }
280 if (desktop->not_show_in)
281 {
282 val = efreet_desktop_string_list_join(desktop->not_show_in);
283 if (val)
284 {
285 efreet_ini_string_set(ini, "NotShowIn", val);
286 FREE(val);
287 }
288 }
289 efreet_desktop_generic_fields_save(desktop, ini);
290 /* When we save the file, it should be updated to the
291 * latest version that we support! */
292 efreet_ini_string_set(ini, "Version", DESKTOP_VERSION);
293
294 if (!efreet_ini_save(ini, desktop->orig_path)) ok = 0;
295 }
296 efreet_ini_free(ini);
297 return ok;
298}
299
300EAPI int
301efreet_desktop_save_as(Efreet_Desktop *desktop, const char *file)
302{
303 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
304 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
305
306 /* If we save data from eet as new, we will be in trouble */
307 if (desktop->eet) return 0;
308
309 IF_FREE(desktop->orig_path);
310 desktop->orig_path = strdup(file);
311 return efreet_desktop_save(desktop);
312}
313
314EAPI void
315efreet_desktop_free(Efreet_Desktop *desktop)
316{
317 if (!desktop) return;
318
319 desktop->ref--;
320 if (desktop->ref > 0) return;
321
322 if (desktop->eet)
323 {
324 efreet_cache_desktop_free(desktop);
325 }
326 else
327 {
328 IF_FREE(desktop->orig_path);
329
330 IF_FREE(desktop->version);
331 IF_FREE(desktop->name);
332 IF_FREE(desktop->generic_name);
333 IF_FREE(desktop->comment);
334 IF_FREE(desktop->icon);
335 IF_FREE(desktop->url);
336
337 IF_FREE(desktop->try_exec);
338 IF_FREE(desktop->exec);
339 IF_FREE(desktop->path);
340 IF_FREE(desktop->startup_wm_class);
341
342 IF_FREE_LIST(desktop->only_show_in, eina_stringshare_del);
343 IF_FREE_LIST(desktop->not_show_in, eina_stringshare_del);
344
345 IF_FREE_LIST(desktop->categories, eina_stringshare_del);
346 IF_FREE_LIST(desktop->mime_types, eina_stringshare_del);
347
348 IF_FREE_HASH(desktop->x);
349
350 if (desktop->type_data)
351 {
352 Efreet_Desktop_Type_Info *info;
353 info = eina_list_nth(efreet_desktop_types, desktop->type);
354 if (info->free_func)
355 info->free_func(desktop->type_data);
356 }
357 free(desktop);
358 }
359}
360
361EAPI void
362efreet_desktop_environment_set(const char *environment)
363{
364 if (desktop_environment) eina_stringshare_del(desktop_environment);
365 if (environment) desktop_environment = eina_stringshare_add(environment);
366 else desktop_environment = NULL;
367}
368
369EAPI const char *
370efreet_desktop_environment_get(void)
371{
372 return desktop_environment;
373}
374
375EAPI unsigned int
376efreet_desktop_category_count_get(Efreet_Desktop *desktop)
377{
378 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
379 return eina_list_count(desktop->categories);
380}
381
382EAPI void
383efreet_desktop_category_add(Efreet_Desktop *desktop, const char *category)
384{
385 EINA_SAFETY_ON_NULL_RETURN(desktop);
386 EINA_SAFETY_ON_NULL_RETURN(category);
387
388 if (eina_list_search_unsorted(desktop->categories,
389 EINA_COMPARE_CB(strcmp), category)) return;
390
391 desktop->categories = eina_list_append(desktop->categories,
392 (void *)eina_stringshare_add(category));
393}
394
395EAPI int
396efreet_desktop_category_del(Efreet_Desktop *desktop, const char *category)
397{
398 char *found = NULL;
399
400 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);
401
402 if ((found = eina_list_search_unsorted(desktop->categories,
403 EINA_COMPARE_CB(strcmp), category)))
404 {
405 eina_stringshare_del(found);
406 desktop->categories = eina_list_remove(desktop->categories, found);
407
408 return 1;
409 }
410
411 return 0;
412}
413
414EAPI int
415efreet_desktop_type_add(const char *type, Efreet_Desktop_Type_Parse_Cb parse_func,
416 Efreet_Desktop_Type_Save_Cb save_func,
417 Efreet_Desktop_Type_Free_Cb free_func)
418{
419 int id;
420 Efreet_Desktop_Type_Info *info;
421
422 info = NEW(Efreet_Desktop_Type_Info, 1);
423 if (!info) return 0;
424
425 id = eina_list_count(efreet_desktop_types);
426
427 info->id = id;
428 info->type = eina_stringshare_add(type);
429 info->parse_func = parse_func;
430 info->save_func = save_func;
431 info->free_func = free_func;
432
433 efreet_desktop_types = eina_list_append(efreet_desktop_types, info);
434
435 return id;
436}
437
438EAPI int
439efreet_desktop_type_alias(int from_type, const char *alias)
440{
441 Efreet_Desktop_Type_Info *info;
442 info = eina_list_nth(efreet_desktop_types, from_type);
443 if (!info) return -1;
444
445 return efreet_desktop_type_add(alias, info->parse_func, info->save_func, info->free_func);
446}
447
448EAPI Eina_Bool
449efreet_desktop_x_field_set(Efreet_Desktop *desktop, const char *key, const char *data)
450{
451 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, EINA_FALSE);
452 EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), EINA_FALSE);
453
454 if (!desktop->x)
455 desktop->x = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
456
457 eina_hash_del_by_key(desktop->x, key);
458 eina_hash_add(desktop->x, key, eina_stringshare_add(data));
459
460 return EINA_TRUE;
461}
462
463EAPI const char *
464efreet_desktop_x_field_get(Efreet_Desktop *desktop, const char *key)
465{
466 const char *ret;
467
468 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL);
469 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->x, NULL);
470 EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), NULL);
471
472 ret = eina_hash_find(desktop->x, key);
473 if (!ret)
474 return NULL;
475
476 return eina_stringshare_add(ret);
477}
478
479EAPI Eina_Bool
480efreet_desktop_x_field_del(Efreet_Desktop *desktop, const char *key)
481{
482 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, EINA_FALSE);
483 EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), EINA_FALSE);
484 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->x, EINA_FALSE);
485
486 return eina_hash_del_by_key(desktop->x, key);
487}
488
489EAPI void *
490efreet_desktop_type_data_get(Efreet_Desktop *desktop)
491{
492 EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL);
493 return desktop->type_data;
494}
495
496EAPI Eina_List *
497efreet_desktop_string_list_parse(const char *string)
498{
499 Eina_List *list = NULL;
500 char *tmp;
501 char *s, *p;
502 size_t len;
503
504 EINA_SAFETY_ON_NULL_RETURN_VAL(string, NULL);
505
506 len = strlen(string) + 1;
507 tmp = alloca(len);
508 memcpy(tmp, string, len);
509 s = tmp;
510
511 while ((p = strchr(s, ';')))
512 {
513 if (p > tmp && *(p-1) == '\\') continue;
514 *p = '\0';
515 list = eina_list_append(list, (void *)eina_stringshare_add(s));
516 s = p + 1;
517 }
518 /* If this is true, the .desktop file does not follow the standard */
519 if (*s)
520 {
521#ifdef STRICT_SPEC
522 WRN("[Efreet]: Found a string list without ';' "
523 "at the end: %s", string);
524#endif
525 list = eina_list_append(list, (void *)eina_stringshare_add(s));
526 }
527
528 return list;
529}
530
531EAPI char *
532efreet_desktop_string_list_join(Eina_List *list)
533{
534 Eina_List *l;
535 const char *elem;
536 char *string;
537 size_t size, pos, len;
538
539 if (!list) return strdup("");
540
541 size = 1024;
542 string = malloc(size);
543 if (!string) return NULL;
544 pos = 0;
545
546 EINA_LIST_FOREACH(list, l, elem)
547 {
548 len = strlen(elem);
549 /* +1 for ';' */
550 if ((len + pos + 1) >= size)
551 {
552 char *tmp;
553 size = len + pos + 1024;
554 tmp = realloc(string, size);
555 if (!tmp)
556 {
557 free(string);
558 return NULL;
559 }
560 string = tmp;
561 }
562 strcpy(string + pos, elem);
563 pos += len;
564 strcpy(string + pos, ";");
565 pos += 1;
566 }
567 return string;
568}
569
570/**
571 * @internal
572 * @param desktop The desktop to fill
573 * @return Returns 1 on success, 0 on failure
574 * @brief initialize an Efreet_Desktop from the contents of @a file
575 */
576static int
577efreet_desktop_read(Efreet_Desktop *desktop)
578{
579 Efreet_Ini *ini;
580 int error = 0;
581 int ok;
582
583 ini = efreet_ini_new(desktop->orig_path);
584 if (!ini) return 0;
585 if (!ini->data)
586 {
587 efreet_ini_free(ini);
588 return 0;
589 }
590
591 ok = efreet_ini_section_set(ini, "Desktop Entry");
592 if (!ok) ok = efreet_ini_section_set(ini, "KDE Desktop Entry");
593 if (!ok)
594 {
595 ERR("efreet_desktop_new error: no Desktop Entry section");
596 error = 1;
597 }
598
599 if (!error)
600 {
601 Efreet_Desktop_Type_Info *info;
602
603 info = efreet_desktop_type_parse(efreet_ini_string_get(ini, "Type"));
604 if (info)
605 {
606 const char *val;
607
608 desktop->type = info->id;
609 val = efreet_ini_string_get(ini, "Version");
610 if (val) desktop->version = strdup(val);
611
612 if (info->parse_func)
613 desktop->type_data = info->parse_func(desktop, ini);
614 }
615 else
616 error = 1;
617 }
618
619 if (!error && !efreet_desktop_generic_fields_parse(desktop, ini)) error = 1;
620 if (!error && !efreet_desktop_environment_check(desktop)) error = 1;
621 if (!error)
622 eina_hash_foreach(ini->section, efreet_desktop_x_fields_parse, desktop);
623
624 efreet_ini_free(ini);
625
626 desktop->load_time = ecore_file_mod_time(desktop->orig_path);
627
628 if (error) return 0;
629
630 return 1;
631}
632
633/**
634 * @internal
635 * @param type_str the type as a string
636 * @return the parsed type
637 * @brief parse the type string into an Efreet_Desktop_Type
638 */
639static Efreet_Desktop_Type_Info *
640efreet_desktop_type_parse(const char *type_str)
641{
642 Efreet_Desktop_Type_Info *info;
643 Eina_List *l;
644
645 if (!type_str) return NULL;
646
647 EINA_LIST_FOREACH(efreet_desktop_types, l, info)
648 {
649 if (!strcmp(info->type, type_str))
650 return info;
651 }
652
653 return NULL;
654}
655
656/**
657 * @internal
658 * @brief Free an Efreet Desktop_Type_Info struct
659 */
660static void
661efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info)
662{
663 if (!info) return;
664 IF_RELEASE(info->type);
665 free(info);
666}
667
668/**
669 * @internal
670 * @param desktop the Efreet_Desktop to store parsed fields in
671 * @param ini the Efreet_Ini to parse fields from
672 * @return No value
673 * @brief Parse application specific desktop fields
674 */
675static void *
676efreet_desktop_application_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini)
677{
678 const char *val;
679
680 val = efreet_ini_string_get(ini, "TryExec");
681 if (val) desktop->try_exec = strdup(val);
682
683 val = efreet_ini_string_get(ini, "Exec");
684 if (val) desktop->exec = strdup(val);
685
686 val = efreet_ini_string_get(ini, "Path");
687 if (val) desktop->path = strdup(val);
688
689 val = efreet_ini_string_get(ini, "StartupWMClass");
690 if (val) desktop->startup_wm_class = strdup(val);
691
692 val = efreet_ini_string_get(ini, "Categories");
693 if (val)
694 desktop->categories = efreet_desktop_string_list_parse(val);
695 val = efreet_ini_string_get(ini, "MimeType");
696 if (val) desktop->mime_types = efreet_desktop_string_list_parse(val);
697
698 desktop->terminal = efreet_ini_boolean_get(ini, "Terminal");
699 desktop->startup_notify = efreet_ini_boolean_get(ini, "StartupNotify");
700
701 return NULL;
702}
703
704/**
705 * @internal
706 * @param desktop the Efreet_Desktop to save fields from
707 * @param ini the Efreet_Ini to save fields to
708 * @return Returns no value
709 * @brief Save application specific desktop fields
710 */
711static void
712efreet_desktop_application_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini)
713{
714 char *val;
715
716 if (desktop->try_exec)
717 efreet_ini_string_set(ini, "TryExec", desktop->try_exec);
718
719 if (desktop->exec)
720 efreet_ini_string_set(ini, "Exec", desktop->exec);
721
722 if (desktop->path)
723 efreet_ini_string_set(ini, "Path", desktop->path);
724
725 if (desktop->startup_wm_class)
726 efreet_ini_string_set(ini, "StartupWMClass", desktop->startup_wm_class);
727
728 if (desktop->categories)
729 {
730 val = efreet_desktop_string_list_join(desktop->categories);
731 if (val)
732 {
733 efreet_ini_string_set(ini, "Categories", val);
734 FREE(val);
735 }
736 }
737
738 if (desktop->mime_types)
739 {
740 val = efreet_desktop_string_list_join(desktop->mime_types);
741 if (val)
742 {
743 efreet_ini_string_set(ini, "MimeType", val);
744 FREE(val);
745 }
746 }
747
748 efreet_ini_boolean_set(ini, "Terminal", desktop->terminal);
749 efreet_ini_boolean_set(ini, "StartupNotify", desktop->startup_notify);
750}
751
752/**
753 * @internal
754 * @param desktop the Efreet_Desktop to store parsed fields in
755 * @param ini the Efreet_Ini to parse fields from
756 * @return Returns no value
757 * @brief Parse link specific desktop fields
758 */
759static void *
760efreet_desktop_link_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini)
761{
762 const char *val;
763
764 val = efreet_ini_string_get(ini, "URL");
765 if (val) desktop->url = strdup(val);
766 return NULL;
767}
768
769/**
770 * @internal
771 * @param desktop the Efreet_Desktop to save fields from
772 * @param ini the Efreet_Ini to save fields in
773 * @return Returns no value
774 * @brief Save link specific desktop fields
775 */
776static void
777efreet_desktop_link_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini)
778{
779 if (desktop->url) efreet_ini_string_set(ini, "URL", desktop->url);
780}
781
782/**
783 * @internal
784 * @param desktop the Efreet_Desktop to store parsed fields in
785 * @param ini the Efreet_Ini to parse fields from
786 * @return 1 if parsed successfully, 0 otherwise
787 * @brief Parse desktop fields that all types can include
788 */
789static int
790efreet_desktop_generic_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini)
791{
792 const char *val;
793 const char *not_show_in = NULL, *only_show_in = NULL;
794
795 val = efreet_ini_localestring_get(ini, "Name");
796#ifndef STRICT_SPEC
797 if (!val) val = efreet_ini_localestring_get(ini, "_Name");
798#endif
799 if (val) desktop->name = strdup(val);
800 else
801 {
802 ERR("efreet_desktop_generic_fields_parse error: no Name or _Name fields");
803 return 0;
804 }
805
806 val = efreet_ini_localestring_get(ini, "GenericName");
807 if (val) desktop->generic_name = strdup(val);
808
809 val = efreet_ini_localestring_get(ini, "Comment");
810#ifndef STRICT_SPEC
811 if (!val) val = efreet_ini_localestring_get(ini, "_Comment");
812#endif
813 if (val) desktop->comment = strdup(val);
814
815 val = efreet_ini_localestring_get(ini, "Icon");
816 if (val) desktop->icon = strdup(val);
817
818 desktop->no_display = efreet_ini_boolean_get(ini, "NoDisplay");
819 desktop->hidden = efreet_ini_boolean_get(ini, "Hidden");
820
821 only_show_in = efreet_ini_string_get(ini, "OnlyShowIn");
822 not_show_in = efreet_ini_string_get(ini, "NotShowIn");
823 if (only_show_in && not_show_in)
824 WRN("Both OnlyShowIn and NotShowIn in %s, preferring OnlyShowIn", desktop->orig_path);
825 if (only_show_in) desktop->only_show_in = efreet_desktop_string_list_parse(only_show_in);
826 else if (not_show_in) desktop->not_show_in = efreet_desktop_string_list_parse(not_show_in);
827
828 return 1;
829}
830
831/**
832 * @internal
833 * @param desktop the Efreet_Desktop to save fields from
834 * @param ini the Efreet_Ini to save fields to
835 * @return Returns nothing
836 * @brief Save desktop fields that all types can include
837 */
838static void
839efreet_desktop_generic_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini)
840{
841 const char *val;
842
843 if (desktop->name)
844 {
845 efreet_ini_localestring_set(ini, "Name", desktop->name);
846 val = efreet_ini_string_get(ini, "Name");
847 if (!val)
848 efreet_ini_string_set(ini, "Name", desktop->name);
849 }
850 if (desktop->generic_name)
851 {
852 efreet_ini_localestring_set(ini, "GenericName", desktop->generic_name);
853 val = efreet_ini_string_get(ini, "GenericName");
854 if (!val)
855 efreet_ini_string_set(ini, "GenericName", desktop->generic_name);
856 }
857 if (desktop->comment)
858 {
859 efreet_ini_localestring_set(ini, "Comment", desktop->comment);
860 val = efreet_ini_string_get(ini, "Comment");
861 if (!val)
862 efreet_ini_string_set(ini, "Comment", desktop->comment);
863 }
864 if (desktop->icon)
865 {
866 efreet_ini_localestring_set(ini, "Icon", desktop->icon);
867 val = efreet_ini_string_get(ini, "Icon");
868 if (!val)
869 efreet_ini_string_set(ini, "Icon", desktop->icon);
870 }
871
872 efreet_ini_boolean_set(ini, "NoDisplay", desktop->no_display);
873 efreet_ini_boolean_set(ini, "Hidden", desktop->hidden);
874
875 if (desktop->x) eina_hash_foreach(desktop->x, efreet_desktop_x_fields_save,
876 ini);
877}
878
879/**
880 * @internal
881 * @param node The node to work with
882 * @param desktop The desktop file to work with
883 * @return Returns always true, to be used in eina_hash_foreach()
884 * @brief Parses out an X- key from @a node and stores in @a desktop
885 */
886static Eina_Bool
887efreet_desktop_x_fields_parse(const Eina_Hash *hash EINA_UNUSED, const void *key, void *value, void *fdata)
888{
889 Efreet_Desktop * desktop = fdata;
890
891 if (!desktop) return EINA_TRUE;
892 if (strncmp(key, "X-", 2)) return EINA_TRUE;
893
894 if (!desktop->x)
895 desktop->x = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del));
896 eina_hash_del_by_key(desktop->x, key);
897 eina_hash_add(desktop->x, key, (void *)eina_stringshare_add(value));
898
899 return EINA_TRUE;
900}
901
902/**
903 * @internal
904 * @param node The node to work with
905 * @param ini The ini file to work with
906 * @return Returns no value
907 * @brief Stores an X- key from @a node and stores in @a ini
908 */
909static Eina_Bool
910efreet_desktop_x_fields_save(const Eina_Hash *hash EINA_UNUSED, const void *key, void *value, void *fdata)
911{
912 Efreet_Ini *ini = fdata;
913 efreet_ini_string_set(ini, key, value);
914
915 return EINA_TRUE;
916}
917
918
919/**
920 * @internal
921 * @param ini The Efreet_Ini to parse values from
922 * @return 1 if desktop should be included in current environement, 0 otherwise
923 * @brief Determines if a desktop should be included in the current environment,
924 * based on the values of the OnlyShowIn and NotShowIn fields
925 */
926static int
927efreet_desktop_environment_check(Efreet_Desktop *desktop)
928{
929 Eina_List *list;
930 int found = 0;
931 char *val;
932
933 if (!desktop_environment)
934 {
935 //if (desktop->only_show_in) return 0;
936 return 1;
937 }
938
939 if (desktop->only_show_in)
940 {
941 EINA_LIST_FOREACH(desktop->only_show_in, list, val)
942 {
943 if (!strcmp(val, desktop_environment))
944 {
945 found = 1;
946 break;
947 }
948 }
949 return found;
950 }
951
952
953 if (desktop->not_show_in)
954 {
955 EINA_LIST_FOREACH(desktop->not_show_in, list, val)
956 {
957 if (!strcmp(val, desktop_environment))
958 {
959 found = 1;
960 break;
961 }
962 }
963 return !found;
964 }
965
966 return 1;
967}
diff --git a/src/lib/efreet/efreet_desktop.h b/src/lib/efreet/efreet_desktop.h
new file mode 100644
index 0000000..fbcce45
--- /dev/null
+++ b/src/lib/efreet/efreet_desktop.h
@@ -0,0 +1,371 @@
1#ifndef EFREET_DESKTOP_H
2#define EFREET_DESKTOP_H
3
4/**
5 * @file efreet_desktop.h
6 * @brief Contains the structures and methods used to support the
7 * FDO desktop entry specificiation.
8 * @addtogroup Efreet_Desktop Efreet_Desktop: The FDO Desktop Entry
9 * Specification functions and structures
10 * @ingroup Efreet
11 *
12 * @{
13 */
14
15
16EAPI extern int EFREET_DESKTOP_TYPE_APPLICATION;
17EAPI extern int EFREET_DESKTOP_TYPE_LINK;
18EAPI extern int EFREET_DESKTOP_TYPE_DIRECTORY;
19
20/**
21 * Event id for cache update. All users of efreet_desktop_get must listen to
22 * this event and refetch. The old eet cache will be closed and mem will
23 * be invalidated.
24 */
25EAPI extern int EFREET_EVENT_DESKTOP_CACHE_UPDATE;
26/**
27 * Event id for cache build complete.
28 * @since 1.1.0
29 */
30EAPI extern int EFREET_EVENT_DESKTOP_CACHE_BUILD;
31
32/**