diff options
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/efreet/efreet_desktop_cache_create.c | 465 | ||||
-rw-r--r-- | src/bin/efreet/efreet_icon_cache_create.c | 1070 | ||||
-rw-r--r-- | src/bin/efreet/efreetd.c | 59 | ||||
-rw-r--r-- | src/bin/efreet/efreetd.h | 34 | ||||
-rw-r--r-- | src/bin/efreet/efreetd_cache.c | 575 | ||||
-rw-r--r-- | src/bin/efreet/efreetd_cache.h | 13 | ||||
-rw-r--r-- | src/bin/efreet/efreetd_dbus.c | 262 | ||||
-rw-r--r-- | src/bin/efreet/efreetd_dbus.h | 10 |
8 files changed, 2488 insertions, 0 deletions
diff --git a/src/bin/efreet/efreet_desktop_cache_create.c b/src/bin/efreet/efreet_desktop_cache_create.c new file mode 100644 index 0000000000..db3118ca1d --- /dev/null +++ b/src/bin/efreet/efreet_desktop_cache_create.c | |||
@@ -0,0 +1,465 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | #include <sys/stat.h> | ||
5 | #include <fcntl.h> | ||
6 | #include <unistd.h> | ||
7 | #include <errno.h> | ||
8 | |||
9 | #include <Eina.h> | ||
10 | #include <Eet.h> | ||
11 | #include <Ecore.h> | ||
12 | #include <Ecore_File.h> | ||
13 | |||
14 | #define EFREET_MODULE_LOG_DOM _efreet_desktop_cache_log_dom | ||
15 | static int _efreet_desktop_cache_log_dom = -1; | ||
16 | |||
17 | #include "Efreet.h" | ||
18 | #include "efreet_private.h" | ||
19 | #include "efreet_cache_private.h" | ||
20 | |||
21 | static Eet_Data_Descriptor *edd = NULL; | ||
22 | static Eet_File *ef = NULL; | ||
23 | static Eet_File *util_ef = NULL; | ||
24 | |||
25 | static Eina_Hash *desktops = NULL; | ||
26 | |||
27 | static Eina_Hash *file_ids = NULL; | ||
28 | static Efreet_Cache_Hash *old_file_ids = NULL; | ||
29 | static Eina_Hash *paths = NULL; | ||
30 | |||
31 | static Eina_Hash *mime_types = NULL; | ||
32 | static Eina_Hash *categories = NULL; | ||
33 | static Eina_Hash *startup_wm_class = NULL; | ||
34 | static Eina_Hash *name = NULL; | ||
35 | static Eina_Hash *generic_name = NULL; | ||
36 | static Eina_Hash *comment = NULL; | ||
37 | static Eina_Hash *exec = NULL; | ||
38 | |||
39 | static int | ||
40 | cache_add(const char *path, const char *file_id, int priority EINA_UNUSED, int *changed) | ||
41 | { | ||
42 | Efreet_Desktop *desk; | ||
43 | char *ext; | ||
44 | |||
45 | INF("FOUND: %s", path); | ||
46 | if (file_id) INF(" (id): %s", file_id); | ||
47 | ext = strrchr(path, '.'); | ||
48 | if (!ext || (strcmp(ext, ".desktop") && strcmp(ext, ".directory"))) return 1; | ||
49 | desk = efreet_desktop_new(path); | ||
50 | if (desk) INF(" OK"); | ||
51 | else INF(" FAIL"); | ||
52 | if (!desk) return 1; | ||
53 | if (!desk->eet) | ||
54 | { | ||
55 | /* This file isn't in cache */ | ||
56 | *changed = 1; | ||
57 | INF(" NEW"); | ||
58 | } | ||
59 | else if (ecore_file_mod_time(desk->orig_path) != desk->load_time) | ||
60 | { | ||
61 | efreet_desktop_free(desk); | ||
62 | *changed = 1; | ||
63 | desk = efreet_desktop_uncached_new(path); | ||
64 | if (desk) INF(" CHANGED"); | ||
65 | else INF(" NO UNCACHED"); | ||
66 | } | ||
67 | if (!desk) return 1; | ||
68 | if (file_id && old_file_ids && !eina_hash_find(old_file_ids->hash, file_id)) | ||
69 | { | ||
70 | *changed = 1; | ||
71 | INF(" NOT IN UTILS"); | ||
72 | } | ||
73 | if (!eina_hash_find(paths, desk->orig_path)) | ||
74 | { | ||
75 | if (!eet_data_write(ef, edd, desk->orig_path, desk, 0)) | ||
76 | return 0; | ||
77 | eina_hash_add(paths, desk->orig_path, (void *)1); | ||
78 | } | ||
79 | /* TODO: We should check priority, and not just hope we search in right order */ | ||
80 | /* TODO: We need to find out if prioritized file id has changed because of | ||
81 | * changed search order. */ | ||
82 | if (!desk->hidden && desk->type == EFREET_DESKTOP_TYPE_APPLICATION && | ||
83 | file_id && !eina_hash_find(file_ids, file_id)) | ||
84 | { | ||
85 | Eina_List *l; | ||
86 | char *data; | ||
87 | Efreet_Cache_Array_String *array; | ||
88 | |||
89 | #define ADD_LIST(list, hash) \ | ||
90 | EINA_LIST_FOREACH((list), l, data) \ | ||
91 | { \ | ||
92 | array = eina_hash_find((hash), data); \ | ||
93 | if (!array) \ | ||
94 | array = NEW(Efreet_Cache_Array_String, 1); \ | ||
95 | array->array = realloc(array->array, sizeof (char *) * (array->array_count + 1)); \ | ||
96 | array->array[array->array_count++] = desk->orig_path; \ | ||
97 | eina_hash_set((hash), data, array); \ | ||
98 | } | ||
99 | #define ADD_ELEM(elem, hash) \ | ||
100 | if ((elem)) \ | ||
101 | { \ | ||
102 | data = (elem); \ | ||
103 | array = eina_hash_find((hash), data); \ | ||
104 | if (!array) \ | ||
105 | array = NEW(Efreet_Cache_Array_String, 1); \ | ||
106 | array->array = realloc(array->array, sizeof (char *) * (array->array_count + 1)); \ | ||
107 | array->array[array->array_count++] = desk->orig_path; \ | ||
108 | eina_hash_set((hash), data, array); \ | ||
109 | } | ||
110 | ADD_LIST(desk->mime_types, mime_types); | ||
111 | ADD_LIST(desk->categories, categories); | ||
112 | ADD_ELEM(desk->startup_wm_class, startup_wm_class); | ||
113 | ADD_ELEM(desk->name, name); | ||
114 | ADD_ELEM(desk->generic_name, generic_name); | ||
115 | ADD_ELEM(desk->comment, comment); | ||
116 | ADD_ELEM(desk->exec, exec); | ||
117 | eina_hash_add(file_ids, file_id, desk->orig_path); | ||
118 | eina_hash_add(desktops, desk->orig_path, desk); | ||
119 | } | ||
120 | else | ||
121 | efreet_desktop_free(desk); | ||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | |||
126 | static int | ||
127 | cache_scan(const char *path, const char *base_id, int priority, int recurse, int *changed) | ||
128 | { | ||
129 | char *file_id = NULL; | ||
130 | char id[PATH_MAX]; | ||
131 | char buf[PATH_MAX]; | ||
132 | Eina_Iterator *it; | ||
133 | Eina_File_Direct_Info *info; | ||
134 | |||
135 | if (!ecore_file_is_dir(path)) return 1; | ||
136 | |||
137 | it = eina_file_stat_ls(path); | ||
138 | if (!it) return 1; | ||
139 | |||
140 | id[0] = '\0'; | ||
141 | EINA_ITERATOR_FOREACH(it, info) | ||
142 | { | ||
143 | const char *fname; | ||
144 | |||
145 | fname = info->path + info->name_start; | ||
146 | if (base_id) | ||
147 | { | ||
148 | if (*base_id) | ||
149 | snprintf(id, sizeof(id), "%s-%s", base_id, fname); | ||
150 | else | ||
151 | strcpy(id, fname); | ||
152 | file_id = id; | ||
153 | } | ||
154 | |||
155 | snprintf(buf, sizeof(buf), "%s/%s", path, fname); | ||
156 | if (info->type == EINA_FILE_DIR) | ||
157 | { | ||
158 | if (recurse) | ||
159 | cache_scan(buf, file_id, priority, recurse, changed); | ||
160 | } | ||
161 | else | ||
162 | { | ||
163 | if (!cache_add(buf, file_id, priority, changed)) | ||
164 | { | ||
165 | eina_iterator_free(it); | ||
166 | return 0; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | eina_iterator_free(it); | ||
171 | return 1; | ||
172 | } | ||
173 | |||
174 | static int | ||
175 | cache_lock_file(void) | ||
176 | { | ||
177 | char file[PATH_MAX]; | ||
178 | struct flock fl; | ||
179 | int lockfd; | ||
180 | |||
181 | snprintf(file, sizeof(file), "%s/efreet/desktop_data.lock", efreet_cache_home_get()); | ||
182 | lockfd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | ||
183 | if (lockfd < 0) return -1; | ||
184 | efreet_fsetowner(lockfd); | ||
185 | |||
186 | memset(&fl, 0, sizeof(struct flock)); | ||
187 | fl.l_type = F_WRLCK; | ||
188 | fl.l_whence = SEEK_SET; | ||
189 | if (fcntl(lockfd, F_SETLK, &fl) < 0) | ||
190 | { | ||
191 | INF("LOCKED! You may want to delete %s if this persists", file); | ||
192 | close(lockfd); | ||
193 | return -1; | ||
194 | } | ||
195 | |||
196 | return lockfd; | ||
197 | } | ||
198 | |||
199 | int | ||
200 | main(int argc, char **argv) | ||
201 | { | ||
202 | /* TODO: | ||
203 | * - Add file monitor on files, so that we catch changes on files | ||
204 | * during whilst this program runs. | ||
205 | * - Maybe linger for a while to reduce number of cache re-creates. | ||
206 | */ | ||
207 | Efreet_Cache_Hash hash; | ||
208 | Efreet_Cache_Version version; | ||
209 | Eina_List *dirs = NULL; | ||
210 | Eina_List *systemdirs = NULL; | ||
211 | Eina_List *extra_dirs = NULL; | ||
212 | Eina_List *l = NULL; | ||
213 | int priority = 0; | ||
214 | char *dir = NULL; | ||
215 | char *path; | ||
216 | int lockfd = -1, tmpfd; | ||
217 | int changed = 0; | ||
218 | int i; | ||
219 | char file[PATH_MAX] = { '\0' }; | ||
220 | char util_file[PATH_MAX] = { '\0' }; | ||
221 | |||
222 | if (!eina_init()) goto eina_error; | ||
223 | _efreet_desktop_cache_log_dom = | ||
224 | eina_log_domain_register("efreet_desktop_cache", EFREET_DEFAULT_LOG_COLOR); | ||
225 | if (_efreet_desktop_cache_log_dom < 0) | ||
226 | { | ||
227 | EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_desktop_cache."); | ||
228 | return -1; | ||
229 | } | ||
230 | |||
231 | for (i = 1; i < argc; i++) | ||
232 | { | ||
233 | if (!strcmp(argv[i], "-v")) | ||
234 | eina_log_domain_level_set("efreet_desktop_cache", EINA_LOG_LEVEL_DBG); | ||
235 | else if ((!strcmp(argv[i], "-h")) || | ||
236 | (!strcmp(argv[i], "-help")) || | ||
237 | (!strcmp(argv[i], "--h")) || | ||
238 | (!strcmp(argv[i], "--help"))) | ||
239 | { | ||
240 | printf("Options:\n"); | ||
241 | printf(" -v Verbose mode\n"); | ||
242 | printf(" -d dir1 dir2 Extra dirs\n"); | ||
243 | exit(0); | ||
244 | } | ||
245 | else if (!strcmp(argv[i], "-d")) | ||
246 | { | ||
247 | while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-')) | ||
248 | extra_dirs = eina_list_append(extra_dirs, argv[++i]); | ||
249 | } | ||
250 | } | ||
251 | extra_dirs = eina_list_sort(extra_dirs, -1, EINA_COMPARE_CB(strcmp)); | ||
252 | |||
253 | /* init external subsystems */ | ||
254 | if (!eet_init()) goto eet_error; | ||
255 | if (!ecore_init()) goto ecore_error; | ||
256 | |||
257 | efreet_cache_update = 0; | ||
258 | /* finish efreet init */ | ||
259 | if (!efreet_init()) goto efreet_error; | ||
260 | |||
261 | /* create homedir */ | ||
262 | snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get()); | ||
263 | if (!ecore_file_exists(file)) | ||
264 | { | ||
265 | if (!ecore_file_mkpath(file)) goto efreet_error; | ||
266 | efreet_setowner(file); | ||
267 | } | ||
268 | |||
269 | /* lock process, so that we only run one copy of this program */ | ||
270 | lockfd = cache_lock_file(); | ||
271 | if (lockfd == -1) goto efreet_error; | ||
272 | |||
273 | edd = efreet_desktop_edd(); | ||
274 | if (!edd) goto edd_error; | ||
275 | |||
276 | /* read user dirs from old cache */ | ||
277 | ef = eet_open(efreet_desktop_util_cache_file(), EET_FILE_MODE_READ); | ||
278 | if (ef) | ||
279 | { | ||
280 | old_file_ids = eet_data_read(ef, efreet_hash_string_edd(), "file_id"); | ||
281 | eet_close(ef); | ||
282 | } | ||
283 | |||
284 | /* create cache */ | ||
285 | snprintf(file, sizeof(file), "%s.XXXXXX", efreet_desktop_cache_file()); | ||
286 | tmpfd = mkstemp(file); | ||
287 | if (tmpfd < 0) goto error; | ||
288 | close(tmpfd); | ||
289 | ef = eet_open(file, EET_FILE_MODE_READ_WRITE); | ||
290 | if (!ef) goto error; | ||
291 | |||
292 | snprintf(util_file, sizeof(util_file), "%s.XXXXXX", efreet_desktop_util_cache_file()); | ||
293 | tmpfd = mkstemp(util_file); | ||
294 | if (tmpfd < 0) goto error; | ||
295 | close(tmpfd); | ||
296 | util_ef = eet_open(util_file, EET_FILE_MODE_READ_WRITE); | ||
297 | if (!util_ef) goto error; | ||
298 | |||
299 | /* write cache version */ | ||
300 | version.major = EFREET_DESKTOP_UTILS_CACHE_MAJOR; | ||
301 | version.minor = EFREET_DESKTOP_UTILS_CACHE_MINOR; | ||
302 | eet_data_write(util_ef, efreet_version_edd(), EFREET_CACHE_VERSION, &version, 1); | ||
303 | version.major = EFREET_DESKTOP_CACHE_MAJOR; | ||
304 | version.minor = EFREET_DESKTOP_CACHE_MINOR; | ||
305 | eet_data_write(ef, efreet_version_edd(), EFREET_CACHE_VERSION, &version, 1); | ||
306 | |||
307 | desktops = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_desktop_free)); | ||
308 | |||
309 | file_ids = eina_hash_string_superfast_new(NULL); | ||
310 | paths = eina_hash_string_superfast_new(NULL); | ||
311 | |||
312 | mime_types = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
313 | categories = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
314 | startup_wm_class = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
315 | name = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
316 | generic_name = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
317 | comment = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
318 | exec = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); | ||
319 | |||
320 | dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(), | ||
321 | "applications"); | ||
322 | if (!dirs) goto error; | ||
323 | |||
324 | EINA_LIST_FREE(dirs, path) | ||
325 | { | ||
326 | char file_id[PATH_MAX] = { '\0' }; | ||
327 | |||
328 | if (!cache_scan(path, file_id, priority++, 1, &changed)) goto error; | ||
329 | systemdirs = eina_list_append(systemdirs, path); | ||
330 | } | ||
331 | |||
332 | EINA_LIST_FOREACH(extra_dirs, l, path) | ||
333 | if (!cache_scan(path, NULL, priority, 0, &changed)) goto error; | ||
334 | |||
335 | /* store util */ | ||
336 | #define STORE_HASH_ARRAY(_hash) \ | ||
337 | if (eina_hash_population((_hash)) > 0) \ | ||
338 | { \ | ||
339 | Eina_Iterator *it; \ | ||
340 | Efreet_Cache_Array_String array; \ | ||
341 | const char *str; \ | ||
342 | \ | ||
343 | hash.hash = (_hash); \ | ||
344 | eet_data_write(util_ef, efreet_hash_array_string_edd(), #_hash "_hash", &hash, 1); \ | ||
345 | array.array_count = 0; \ | ||
346 | array.array = malloc(eina_hash_population(hash.hash) * sizeof(char *)); \ | ||
347 | it = eina_hash_iterator_key_new(hash.hash); \ | ||
348 | EINA_ITERATOR_FOREACH(it, str) \ | ||
349 | array.array[array.array_count++] = str; \ | ||
350 | eina_iterator_free(it); \ | ||
351 | eet_data_write(util_ef, efreet_array_string_edd(), #_hash "_list", &array, 1); \ | ||
352 | free(array.array); \ | ||
353 | } | ||
354 | STORE_HASH_ARRAY(mime_types); | ||
355 | STORE_HASH_ARRAY(categories); | ||
356 | STORE_HASH_ARRAY(startup_wm_class); | ||
357 | STORE_HASH_ARRAY(name); | ||
358 | STORE_HASH_ARRAY(generic_name); | ||
359 | STORE_HASH_ARRAY(comment); | ||
360 | STORE_HASH_ARRAY(exec); | ||
361 | if (eina_hash_population(file_ids) > 0) | ||
362 | { | ||
363 | hash.hash = file_ids; | ||
364 | eet_data_write(util_ef, efreet_hash_string_edd(), "file_id", &hash, 1); | ||
365 | } | ||
366 | |||
367 | eina_hash_free(mime_types); | ||
368 | eina_hash_free(categories); | ||
369 | eina_hash_free(startup_wm_class); | ||
370 | eina_hash_free(name); | ||
371 | eina_hash_free(generic_name); | ||
372 | eina_hash_free(comment); | ||
373 | eina_hash_free(exec); | ||
374 | |||
375 | if (old_file_ids) | ||
376 | { | ||
377 | eina_hash_free(old_file_ids->hash); | ||
378 | free(old_file_ids); | ||
379 | } | ||
380 | |||
381 | eina_hash_free(file_ids); | ||
382 | eina_hash_free(paths); | ||
383 | |||
384 | eina_hash_free(desktops); | ||
385 | |||
386 | /* check if old and new caches contain the same number of entries */ | ||
387 | if (!changed) | ||
388 | { | ||
389 | Eet_File *old; | ||
390 | |||
391 | old = eet_open(efreet_desktop_cache_file(), EET_FILE_MODE_READ); | ||
392 | if (!old || eet_num_entries(old) != eet_num_entries(ef)) changed = 1; | ||
393 | if (old) eet_close(old); | ||
394 | old = eet_open(efreet_desktop_util_cache_file(), EET_FILE_MODE_READ); | ||
395 | if (!old || eet_num_entries(old) != eet_num_entries(util_ef)) changed = 1; | ||
396 | if (old) eet_close(old); | ||
397 | } | ||
398 | |||
399 | /* cleanup */ | ||
400 | eet_close(util_ef); | ||
401 | eet_close(ef); | ||
402 | |||
403 | /* unlink old cache files */ | ||
404 | if (changed) | ||
405 | { | ||
406 | if (unlink(efreet_desktop_cache_file()) < 0) | ||
407 | { | ||
408 | if (errno != ENOENT) goto error; | ||
409 | } | ||
410 | if (unlink(efreet_desktop_util_cache_file()) < 0) | ||
411 | { | ||
412 | if (errno != ENOENT) goto error; | ||
413 | } | ||
414 | /* rename tmp files to real files */ | ||
415 | if (rename(util_file, efreet_desktop_util_cache_file()) < 0) goto error; | ||
416 | efreet_setowner(efreet_desktop_util_cache_file()); | ||
417 | if (rename(file, efreet_desktop_cache_file()) < 0) goto error; | ||
418 | efreet_setowner(efreet_desktop_cache_file()); | ||
419 | } | ||
420 | else | ||
421 | { | ||
422 | unlink(util_file); | ||
423 | unlink(file); | ||
424 | } | ||
425 | |||
426 | { | ||
427 | char c = 'n'; | ||
428 | |||
429 | if (changed) c = 'c'; | ||
430 | printf("%c\n", c); | ||
431 | } | ||
432 | |||
433 | EINA_LIST_FREE(systemdirs, dir) | ||
434 | eina_stringshare_del(dir); | ||
435 | eina_list_free(extra_dirs); | ||
436 | efreet_shutdown(); | ||
437 | ecore_shutdown(); | ||
438 | eet_shutdown(); | ||
439 | eina_log_domain_unregister(_efreet_desktop_cache_log_dom); | ||
440 | eina_shutdown(); | ||
441 | close(lockfd); | ||
442 | return 0; | ||
443 | error: | ||
444 | IF_FREE(dir); | ||
445 | edd_error: | ||
446 | if (old_file_ids) | ||
447 | { | ||
448 | eina_hash_free(old_file_ids->hash); | ||
449 | free(old_file_ids); | ||
450 | } | ||
451 | efreet_shutdown(); | ||
452 | efreet_error: | ||
453 | ecore_shutdown(); | ||
454 | ecore_error: | ||
455 | eet_shutdown(); | ||
456 | eet_error: | ||
457 | EINA_LIST_FREE(systemdirs, dir) | ||
458 | eina_stringshare_del(dir); | ||
459 | eina_list_free(extra_dirs); | ||
460 | eina_log_domain_unregister(_efreet_desktop_cache_log_dom); | ||
461 | eina_shutdown(); | ||
462 | eina_error: | ||
463 | if (lockfd >= 0) close(lockfd); | ||
464 | return 1; | ||
465 | } | ||
diff --git a/src/bin/efreet/efreet_icon_cache_create.c b/src/bin/efreet/efreet_icon_cache_create.c new file mode 100644 index 0000000000..662dd09469 --- /dev/null +++ b/src/bin/efreet/efreet_icon_cache_create.c | |||
@@ -0,0 +1,1070 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include "efreet_alloca.h" | ||
6 | |||
7 | #include <sys/stat.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <unistd.h> | ||
10 | #include <errno.h> | ||
11 | |||
12 | #include <Eina.h> | ||
13 | #include <Eet.h> | ||
14 | #include <Ecore.h> | ||
15 | #include <Ecore_File.h> | ||
16 | |||
17 | #define EFREET_MODULE_LOG_DOM _efreet_icon_cache_log_dom | ||
18 | static int _efreet_icon_cache_log_dom = -1; | ||
19 | |||
20 | #include "Efreet.h" | ||
21 | #include "efreet_private.h" | ||
22 | #include "efreet_cache_private.h" | ||
23 | |||
24 | static Eina_Array *exts = NULL; | ||
25 | static Eina_Array *extra_dirs = NULL; | ||
26 | static Eina_Array *strs = NULL; | ||
27 | static Eina_Hash *icon_themes = NULL; | ||
28 | |||
29 | static Eina_Bool | ||
30 | cache_directory_modified(Eina_Hash *dirs, const char *dir) | ||
31 | { | ||
32 | Efreet_Cache_Directory *dcache; | ||
33 | struct stat st; | ||
34 | |||
35 | if (!dirs) return EINA_TRUE; | ||
36 | |||
37 | if (stat(dir, &st) < 0) return EINA_FALSE; | ||
38 | dcache = eina_hash_find(dirs, dir); | ||
39 | if (!dcache) | ||
40 | { | ||
41 | dcache = malloc(sizeof (Efreet_Cache_Directory)); | ||
42 | if (!dcache) return EINA_TRUE; | ||
43 | |||
44 | dcache->modified_time = (long long) st.st_mtime; | ||
45 | eina_hash_add(dirs, dir, dcache); | ||
46 | } | ||
47 | else if (dcache->modified_time == (long long) st.st_mtime) return EINA_FALSE; | ||
48 | dcache->modified_time = st.st_mtime; | ||
49 | |||
50 | return EINA_TRUE; | ||
51 | } | ||
52 | |||
53 | static Eina_Bool | ||
54 | cache_extension_lookup(const char *ext) | ||
55 | { | ||
56 | unsigned int i; | ||
57 | |||
58 | for (i = 0; i < exts->count; ++i) | ||
59 | if (!strcmp(exts->data[i], ext)) | ||
60 | return EINA_TRUE; | ||
61 | return EINA_FALSE; | ||
62 | } | ||
63 | |||
64 | static Eina_Bool | ||
65 | cache_fallback_scan_dir(Eina_Hash *icons, Eina_Hash *dirs, const char *dir) | ||
66 | { | ||
67 | Eina_Iterator *it; | ||
68 | Eina_File_Direct_Info *entry; | ||
69 | |||
70 | if (!cache_directory_modified(dirs, dir)) return EINA_TRUE; | ||
71 | |||
72 | it = eina_file_stat_ls(dir); | ||
73 | if (!it) return EINA_TRUE; | ||
74 | |||
75 | EINA_ITERATOR_FOREACH(it, entry) | ||
76 | { | ||
77 | Efreet_Cache_Fallback_Icon *icon; | ||
78 | char *name; | ||
79 | char *ext; | ||
80 | unsigned int i; | ||
81 | |||
82 | if (entry->type == EINA_FILE_DIR) | ||
83 | continue; | ||
84 | |||
85 | ext = strrchr(entry->path + entry->name_start, '.'); | ||
86 | if (!ext || !cache_extension_lookup(ext)) | ||
87 | continue; | ||
88 | |||
89 | /* icon with known extension */ | ||
90 | name = entry->path + entry->name_start; | ||
91 | *ext = '\0'; | ||
92 | |||
93 | icon = eina_hash_find(icons, name); | ||
94 | if (!icon) | ||
95 | { | ||
96 | icon = NEW(Efreet_Cache_Fallback_Icon, 1); | ||
97 | icon->theme = NULL; | ||
98 | eina_hash_add(icons, name, icon); | ||
99 | } | ||
100 | |||
101 | *ext = '.'; | ||
102 | |||
103 | for (i = 0; i < icon->icons_count; ++i) | ||
104 | if (!strcmp(icon->icons[i], entry->path)) | ||
105 | break; | ||
106 | |||
107 | if (i != icon->icons_count) | ||
108 | continue; | ||
109 | |||
110 | icon->icons = realloc(icon->icons, sizeof (char *) * (icon->icons_count + 1)); | ||
111 | icon->icons[icon->icons_count] = eina_stringshare_add(entry->path); | ||
112 | eina_array_push(strs, icon->icons[icon->icons_count++]); | ||
113 | } | ||
114 | |||
115 | eina_iterator_free(it); | ||
116 | |||
117 | return EINA_TRUE; | ||
118 | } | ||
119 | |||
120 | static Eina_Bool | ||
121 | cache_fallback_scan(Eina_Hash *icons, Eina_Hash *dirs) | ||
122 | { | ||
123 | unsigned int i; | ||
124 | Eina_List *xdg_dirs, *l; | ||
125 | const char *dir; | ||
126 | char path[PATH_MAX]; | ||
127 | |||
128 | for (i = 0; i < extra_dirs->count; i++) | ||
129 | cache_fallback_scan_dir(icons, dirs, extra_dirs->data[i]); | ||
130 | |||
131 | cache_fallback_scan_dir(icons, dirs, efreet_icon_deprecated_user_dir_get()); | ||
132 | cache_fallback_scan_dir(icons, dirs, efreet_icon_user_dir_get()); | ||
133 | |||
134 | xdg_dirs = efreet_data_dirs_get(); | ||
135 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
136 | { | ||
137 | snprintf(path, sizeof(path), "%s/icons", dir); | ||
138 | cache_fallback_scan_dir(icons, dirs, path); | ||
139 | } | ||
140 | |||
141 | #ifndef STRICT_SPEC | ||
142 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
143 | { | ||
144 | snprintf(path, sizeof(path), "%s/pixmaps", dir); | ||
145 | cache_fallback_scan_dir(icons, dirs, path); | ||
146 | } | ||
147 | #endif | ||
148 | |||
149 | cache_fallback_scan_dir(icons, dirs, "/usr/share/pixmaps"); | ||
150 | |||
151 | return EINA_TRUE; | ||
152 | } | ||
153 | |||
154 | static Eina_Bool | ||
155 | check_fallback_changed(Efreet_Cache_Icon_Theme *theme) | ||
156 | { | ||
157 | unsigned int i; | ||
158 | Eina_List *xdg_dirs, *l; | ||
159 | const char *dir; | ||
160 | char path[PATH_MAX]; | ||
161 | |||
162 | /* Check if the dirs we have cached are changed */ | ||
163 | if (theme->dirs) | ||
164 | { | ||
165 | Eina_Iterator *it; | ||
166 | Eina_Bool changed = EINA_FALSE; | ||
167 | |||
168 | it = eina_hash_iterator_key_new(theme->dirs); | ||
169 | EINA_ITERATOR_FOREACH(it, dir) | ||
170 | { | ||
171 | changed = !ecore_file_exists(dir); | ||
172 | if (changed) break; | ||
173 | changed = cache_directory_modified(theme->dirs, dir); | ||
174 | if (changed) break; | ||
175 | } | ||
176 | eina_iterator_free(it); | ||
177 | if (changed) return EINA_TRUE; | ||
178 | } | ||
179 | |||
180 | /* Check if spec dirs have changed */ | ||
181 | for (i = 0; i < extra_dirs->count; i++) | ||
182 | if (cache_directory_modified(theme->dirs, extra_dirs->data[i])) return EINA_TRUE; | ||
183 | |||
184 | if (cache_directory_modified(theme->dirs, efreet_icon_deprecated_user_dir_get())) return EINA_TRUE; | ||
185 | if (cache_directory_modified(theme->dirs, efreet_icon_user_dir_get())) return EINA_TRUE; | ||
186 | |||
187 | xdg_dirs = efreet_data_dirs_get(); | ||
188 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
189 | { | ||
190 | snprintf(path, sizeof(path), "%s/icons", dir); | ||
191 | if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE; | ||
192 | } | ||
193 | |||
194 | #ifndef STRICT_SPEC | ||
195 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
196 | { | ||
197 | snprintf(path, sizeof(path), "%s/pixmaps", dir); | ||
198 | if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE; | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | if (cache_directory_modified(theme->dirs, "/usr/share/pixmaps")) return EINA_TRUE; | ||
203 | return EINA_FALSE; | ||
204 | } | ||
205 | |||
206 | static Eina_Bool | ||
207 | cache_scan_path_dir(Efreet_Icon_Theme *theme, | ||
208 | const char *path, | ||
209 | Efreet_Icon_Theme_Directory *dir, | ||
210 | Eina_Hash *icons) | ||
211 | { | ||
212 | Eina_Iterator *it; | ||
213 | char buf[PATH_MAX]; | ||
214 | Eina_File_Direct_Info *entry; | ||
215 | |||
216 | snprintf(buf, sizeof(buf), "%s/%s", path, dir->name); | ||
217 | |||
218 | it = eina_file_stat_ls(buf); | ||
219 | if (!it) return EINA_TRUE; | ||
220 | |||
221 | EINA_ITERATOR_FOREACH(it, entry) | ||
222 | { | ||
223 | Efreet_Cache_Icon *icon; | ||
224 | char *name; | ||
225 | char *ext; | ||
226 | unsigned int i; | ||
227 | |||
228 | if (entry->type == EINA_FILE_DIR) | ||
229 | continue; | ||
230 | |||
231 | ext = strrchr(entry->path + entry->name_start, '.'); | ||
232 | if (!ext || !cache_extension_lookup(ext)) | ||
233 | continue; | ||
234 | |||
235 | /* icon with known extension */ | ||
236 | name = entry->path + entry->name_start; | ||
237 | *ext = '\0'; | ||
238 | |||
239 | icon = eina_hash_find(icons, name); | ||
240 | if (!icon) | ||
241 | { | ||
242 | icon = NEW(Efreet_Cache_Icon, 1); | ||
243 | icon->theme = eina_stringshare_add(theme->name.internal); | ||
244 | eina_array_push(strs, icon->theme); | ||
245 | eina_hash_add(icons, name, icon); | ||
246 | } | ||
247 | |||
248 | /* find if we have the same icon in another type */ | ||
249 | for (i = 0; i < icon->icons_count; ++i) | ||
250 | { | ||
251 | if ((icon->icons[i]->type == dir->type) && | ||
252 | (icon->icons[i]->normal == dir->size.normal) && | ||
253 | (icon->icons[i]->max == dir->size.max) && | ||
254 | (icon->icons[i]->min == dir->size.min)) | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | *ext = '.'; | ||
259 | |||
260 | if (i != icon->icons_count) | ||
261 | { | ||
262 | unsigned int j; | ||
263 | |||
264 | /* check if the path already exist */ | ||
265 | for (j = 0; j < icon->icons[i]->paths_count; ++j) | ||
266 | if (!strcmp(icon->icons[i]->paths[j], entry->path)) | ||
267 | break; | ||
268 | |||
269 | if (j != icon->icons[i]->paths_count) | ||
270 | continue; | ||
271 | |||
272 | /* If we are inherited, check if we already have extension */ | ||
273 | if (strcmp(icon->theme, theme->name.internal)) | ||
274 | { | ||
275 | const char *ext2; | ||
276 | int has_ext = 0; | ||
277 | for (j = 0; j < icon->icons[i]->paths_count; ++j) | ||
278 | { | ||
279 | ext2 = strrchr(icon->icons[i]->paths[j], '.'); | ||
280 | if (ext2) | ||
281 | { | ||
282 | ext2++; | ||
283 | has_ext = !strcmp((ext + 1), ext2); | ||
284 | if (has_ext) break; | ||
285 | } | ||
286 | } | ||
287 | if (has_ext) | ||
288 | continue; | ||
289 | } | ||
290 | } | ||
291 | /* no icon match so add a new one */ | ||
292 | /* only allow to add new icon for main theme | ||
293 | * if we allow inherited theme to add new icons, | ||
294 | * we will get weird effects when icon scales | ||
295 | */ | ||
296 | else if (!strcmp(icon->theme, theme->name.internal)) | ||
297 | { | ||
298 | icon->icons = realloc(icon->icons, | ||
299 | sizeof (Efreet_Cache_Icon_Element*) * (++icon->icons_count)); | ||
300 | icon->icons[i] = NEW(Efreet_Cache_Icon_Element, 1); | ||
301 | icon->icons[i]->type = dir->type; | ||
302 | icon->icons[i]->normal = dir->size.normal; | ||
303 | icon->icons[i]->min = dir->size.min; | ||
304 | icon->icons[i]->max = dir->size.max; | ||
305 | icon->icons[i]->paths = NULL; | ||
306 | icon->icons[i]->paths_count = 0; | ||
307 | } | ||
308 | else | ||
309 | { | ||
310 | continue; | ||
311 | } | ||
312 | |||
313 | /* and finally store the path */ | ||
314 | icon->icons[i]->paths = realloc(icon->icons[i]->paths, | ||
315 | sizeof (char*) * (icon->icons[i]->paths_count + 1)); | ||
316 | icon->icons[i]->paths[icon->icons[i]->paths_count] = eina_stringshare_add(entry->path); | ||
317 | eina_array_push(strs, icon->icons[i]->paths[icon->icons[i]->paths_count++]); | ||
318 | } | ||
319 | |||
320 | eina_iterator_free(it); | ||
321 | |||
322 | return EINA_TRUE; | ||
323 | } | ||
324 | |||
325 | static Eina_Bool | ||
326 | cache_scan_path(Efreet_Icon_Theme *theme, Eina_Hash *icons, const char *path) | ||
327 | { | ||
328 | Eina_List *l; | ||
329 | Efreet_Icon_Theme_Directory *dir; | ||
330 | |||
331 | EINA_LIST_FOREACH(theme->directories, l, dir) | ||
332 | if (!cache_scan_path_dir(theme, path, dir, icons)) return EINA_FALSE; | ||
333 | |||
334 | return EINA_TRUE; | ||
335 | } | ||
336 | |||
337 | static Eina_Bool | ||
338 | cache_scan(Efreet_Icon_Theme *theme, Eina_Hash *themes, Eina_Hash *icons) | ||
339 | { | ||
340 | Eina_List *l; | ||
341 | const char *path; | ||
342 | const char *name; | ||
343 | |||
344 | if (!theme) return EINA_TRUE; | ||
345 | if (eina_hash_find(themes, theme->name.internal)) return EINA_TRUE; | ||
346 | eina_hash_direct_add(themes, theme->name.internal, theme); | ||
347 | |||
348 | /* scan theme */ | ||
349 | EINA_LIST_FOREACH(theme->paths, l, path) | ||
350 | if (!cache_scan_path(theme, icons, path)) return EINA_FALSE; | ||
351 | |||
352 | /* scan inherits */ | ||
353 | if (theme->inherits) | ||
354 | { | ||
355 | EINA_LIST_FOREACH(theme->inherits, l, name) | ||
356 | { | ||
357 | Efreet_Icon_Theme *inherit; | ||
358 | |||
359 | inherit = eina_hash_find(icon_themes, name); | ||
360 | if (!inherit) | ||
361 | INF("Theme `%s` not found for `%s`.", | ||
362 | name, theme->name.internal); | ||
363 | if (!cache_scan(inherit, themes, icons)) return EINA_FALSE; | ||
364 | } | ||
365 | } | ||
366 | else if (strcmp(theme->name.internal, "hicolor")) | ||
367 | { | ||
368 | theme = eina_hash_find(icon_themes, "hicolor"); | ||
369 | if (!cache_scan(theme, themes, icons)) return EINA_FALSE; | ||
370 | } | ||
371 | |||
372 | return EINA_TRUE; | ||
373 | } | ||
374 | |||
375 | static Eina_Bool | ||
376 | check_changed(Efreet_Cache_Icon_Theme *theme) | ||
377 | { | ||
378 | Eina_List *l; | ||
379 | const char *name; | ||
380 | |||
381 | if (!theme) return EINA_FALSE; | ||
382 | |||
383 | if (theme->changed) return EINA_TRUE; | ||
384 | if (theme->theme.inherits) | ||
385 | { | ||
386 | EINA_LIST_FOREACH(theme->theme.inherits, l, name) | ||
387 | { | ||
388 | Efreet_Cache_Icon_Theme *inherit; | ||
389 | |||
390 | inherit = eina_hash_find(icon_themes, name); | ||
391 | if (!inherit) | ||
392 | INF("Theme `%s` not found for `%s`.", | ||
393 | name, theme->theme.name.internal); | ||
394 | if (check_changed(inherit)) return EINA_TRUE; | ||
395 | } | ||
396 | } | ||
397 | else if (strcmp(theme->theme.name.internal, "hicolor")) | ||
398 | { | ||
399 | theme = eina_hash_find(icon_themes, "hicolor"); | ||
400 | if (check_changed(theme)) return EINA_TRUE; | ||
401 | } | ||
402 | return EINA_FALSE; | ||
403 | } | ||
404 | |||
405 | static Efreet_Icon_Theme_Directory * | ||
406 | icon_theme_directory_new(Efreet_Ini *ini, const char *name) | ||
407 | { | ||
408 | Efreet_Icon_Theme_Directory *dir; | ||
409 | int val; | ||
410 | const char *tmp; | ||
411 | |||
412 | if (!ini) return NULL; | ||
413 | |||
414 | dir = NEW(Efreet_Icon_Theme_Directory, 1); | ||
415 | if (!dir) return NULL; | ||
416 | dir->name = eina_stringshare_add(name); | ||
417 | eina_array_push(strs, dir->name); | ||
418 | |||
419 | efreet_ini_section_set(ini, name); | ||
420 | |||
421 | tmp = efreet_ini_string_get(ini, "Context"); | ||
422 | if (tmp) | ||
423 | { | ||
424 | if (!strcasecmp(tmp, "Actions")) | ||
425 | dir->context = EFREET_ICON_THEME_CONTEXT_ACTIONS; | ||
426 | |||
427 | else if (!strcasecmp(tmp, "Devices")) | ||
428 | dir->context = EFREET_ICON_THEME_CONTEXT_DEVICES; | ||
429 | |||
430 | else if (!strcasecmp(tmp, "FileSystems")) | ||
431 | dir->context = EFREET_ICON_THEME_CONTEXT_FILESYSTEMS; | ||
432 | |||
433 | else if (!strcasecmp(tmp, "MimeTypes")) | ||
434 | dir->context = EFREET_ICON_THEME_CONTEXT_MIMETYPES; | ||
435 | } | ||
436 | |||
437 | /* Threshold is fallback */ | ||
438 | dir->type = EFREET_ICON_SIZE_TYPE_THRESHOLD; | ||
439 | |||
440 | tmp = efreet_ini_string_get(ini, "Type"); | ||
441 | if (tmp) | ||
442 | { | ||
443 | if (!strcasecmp(tmp, "Fixed")) | ||
444 | dir->type = EFREET_ICON_SIZE_TYPE_FIXED; | ||
445 | |||
446 | else if (!strcasecmp(tmp, "Scalable")) | ||
447 | dir->type = EFREET_ICON_SIZE_TYPE_SCALABLE; | ||
448 | } | ||
449 | |||
450 | dir->size.normal = efreet_ini_int_get(ini, "Size"); | ||
451 | |||
452 | if (dir->type == EFREET_ICON_SIZE_TYPE_THRESHOLD) | ||
453 | { | ||
454 | val = efreet_ini_int_get(ini, "Threshold"); | ||
455 | if (val < 0) val = 2; | ||
456 | dir->size.max = dir->size.normal + val; | ||
457 | dir->size.min = dir->size.normal - val; | ||
458 | } | ||
459 | else if (dir->type == EFREET_ICON_SIZE_TYPE_SCALABLE) | ||
460 | { | ||
461 | val = efreet_ini_int_get(ini, "MinSize"); | ||
462 | if (val < 0) dir->size.min = dir->size.normal; | ||
463 | else dir->size.min = val; | ||
464 | |||
465 | val = efreet_ini_int_get(ini, "MaxSize"); | ||
466 | if (val < 0) dir->size.max = dir->size.normal; | ||
467 | else dir->size.max = val; | ||
468 | } | ||
469 | |||
470 | return dir; | ||
471 | } | ||
472 | |||
473 | static Eina_Bool | ||
474 | icon_theme_index_read(Efreet_Cache_Icon_Theme *theme, const char *path) | ||
475 | { | ||
476 | Efreet_Ini *ini; | ||
477 | Efreet_Icon_Theme_Directory *dir; | ||
478 | const char *tmp; | ||
479 | struct stat st; | ||
480 | |||
481 | if (!theme || !path) return EINA_FALSE; | ||
482 | |||
483 | if (stat(path, &st) < 0) return EINA_FALSE; | ||
484 | if (theme->path && !strcmp(theme->path, path) && theme->last_cache_check >= (long long) st.st_mtime) | ||
485 | { | ||
486 | /* no change */ | ||
487 | theme->valid = 1; | ||
488 | return EINA_TRUE; | ||
489 | } | ||
490 | if (!theme->path || strcmp(theme->path, path)) | ||
491 | { | ||
492 | theme->path = eina_stringshare_add(path); | ||
493 | eina_array_push(strs, theme->path); | ||
494 | } | ||
495 | if ((long long) st.st_mtime > theme->last_cache_check) | ||
496 | theme->last_cache_check = (long long) st.st_mtime; | ||
497 | theme->changed = 1; | ||
498 | |||
499 | ini = efreet_ini_new(path); | ||
500 | if (!ini) return EINA_FALSE; | ||
501 | if (!ini->data) | ||
502 | { | ||
503 | efreet_ini_free(ini); | ||
504 | return EINA_FALSE; | ||
505 | } | ||
506 | |||
507 | efreet_ini_section_set(ini, "Icon Theme"); | ||
508 | tmp = efreet_ini_localestring_get(ini, "Name"); | ||
509 | if (tmp) | ||
510 | { | ||
511 | theme->theme.name.name = eina_stringshare_add(tmp); | ||
512 | eina_array_push(strs, theme->theme.name.name); | ||
513 | } | ||
514 | |||
515 | tmp = efreet_ini_localestring_get(ini, "Comment"); | ||
516 | if (tmp) | ||
517 | { | ||
518 | theme->theme.comment = eina_stringshare_add(tmp); | ||
519 | eina_array_push(strs, theme->theme.comment); | ||
520 | } | ||
521 | |||
522 | tmp = efreet_ini_string_get(ini, "Example"); | ||
523 | if (tmp) | ||
524 | { | ||
525 | theme->theme.example_icon = eina_stringshare_add(tmp); | ||
526 | eina_array_push(strs, theme->theme.example_icon); | ||
527 | } | ||
528 | |||
529 | theme->hidden = efreet_ini_boolean_get(ini, "Hidden"); | ||
530 | |||
531 | theme->valid = 1; | ||
532 | |||
533 | /* Check the inheritance. If there is none we inherit from the hicolor theme */ | ||
534 | tmp = efreet_ini_string_get(ini, "Inherits"); | ||
535 | if (tmp) | ||
536 | { | ||
537 | char *t, *s, *p; | ||
538 | const char *i; | ||
539 | size_t len; | ||
540 | |||
541 | len = strlen(tmp) + 1; | ||
542 | t = alloca(len); | ||
543 | memcpy(t, tmp, len); | ||
544 | s = t; | ||
545 | p = strchr(s, ','); | ||
546 | |||
547 | while (p) | ||
548 | { | ||
549 | *p = '\0'; | ||
550 | |||
551 | i = eina_stringshare_add(s); | ||
552 | theme->theme.inherits = eina_list_append(theme->theme.inherits, i); | ||
553 | eina_array_push(strs, i); | ||
554 | s = ++p; | ||
555 | p = strchr(s, ','); | ||
556 | } | ||
557 | i = eina_stringshare_add(s); | ||
558 | theme->theme.inherits = eina_list_append(theme->theme.inherits, i); | ||
559 | eina_array_push(strs, i); | ||
560 | } | ||
561 | |||
562 | /* make sure this one is done last as setting the directory will change | ||
563 | * the ini section ... */ | ||
564 | tmp = efreet_ini_string_get(ini, "Directories"); | ||
565 | if (tmp) | ||
566 | { | ||
567 | char *t, *s, *p; | ||
568 | size_t len; | ||
569 | |||
570 | len = strlen(tmp) + 1; | ||
571 | t = alloca(len); | ||
572 | memcpy(t, tmp, len); | ||
573 | s = t; | ||
574 | p = s; | ||
575 | |||
576 | while ((p) && (*s)) | ||
577 | { | ||
578 | p = strchr(s, ','); | ||
579 | |||
580 | if (p) *p = '\0'; | ||
581 | |||
582 | dir = icon_theme_directory_new(ini, s); | ||
583 | if (!dir) goto error; | ||
584 | theme->theme.directories = eina_list_append(theme->theme.directories, dir); | ||
585 | |||
586 | if (p) s = ++p; | ||
587 | } | ||
588 | } | ||
589 | |||
590 | error: | ||
591 | efreet_ini_free(ini); | ||
592 | |||
593 | return EINA_TRUE; | ||
594 | } | ||
595 | |||
596 | static Eina_Bool | ||
597 | cache_theme_scan(const char *dir) | ||
598 | { | ||
599 | Eina_Iterator *it; | ||
600 | Eina_File_Direct_Info *entry; | ||
601 | |||
602 | it = eina_file_stat_ls(dir); | ||
603 | if (!it) return EINA_TRUE; | ||
604 | |||
605 | EINA_ITERATOR_FOREACH(it, entry) | ||
606 | { | ||
607 | Efreet_Cache_Icon_Theme *theme; | ||
608 | const char *name; | ||
609 | const char *path; | ||
610 | char buf[PATH_MAX]; | ||
611 | struct stat st; | ||
612 | |||
613 | if (stat(entry->path, &st) < 0) continue; | ||
614 | |||
615 | if ((entry->type != EINA_FILE_DIR) && | ||
616 | (entry->type != EINA_FILE_LNK)) | ||
617 | continue; | ||
618 | |||
619 | name = entry->path + entry->name_start; | ||
620 | theme = eina_hash_find(icon_themes, name); | ||
621 | |||
622 | if (!theme) | ||
623 | { | ||
624 | theme = NEW(Efreet_Cache_Icon_Theme, 1); | ||
625 | theme->theme.name.internal = eina_stringshare_add(name); | ||
626 | eina_array_push(strs, theme->theme.name.internal); | ||
627 | eina_hash_direct_add(icon_themes, | ||
628 | (void *)theme->theme.name.internal, theme); | ||
629 | theme->changed = 1; | ||
630 | } | ||
631 | if ((long long) st.st_mtime > theme->last_cache_check) | ||
632 | { | ||
633 | theme->last_cache_check = (long long) st.st_mtime; | ||
634 | theme->changed = 1; | ||
635 | } | ||
636 | |||
637 | /* TODO: We need to handle change in order of included paths */ | ||
638 | if (!eina_list_search_unsorted(theme->theme.paths, EINA_COMPARE_CB(strcmp), entry->path)) | ||
639 | { | ||
640 | path = eina_stringshare_add(entry->path); | ||
641 | theme->theme.paths = eina_list_append(theme->theme.paths, path); | ||
642 | eina_array_push(strs, path); | ||
643 | theme->changed = 1; | ||
644 | } | ||
645 | |||
646 | /* we're already valid so no reason to check for an index.theme file */ | ||
647 | if (theme->valid) continue; | ||
648 | |||
649 | /* if the index.theme file exists we parse it into the theme */ | ||
650 | memcpy(buf, entry->path, entry->path_length); | ||
651 | memcpy(buf + entry->path_length, "/index.theme", sizeof("/index.theme")); | ||
652 | if (ecore_file_exists(buf)) | ||
653 | { | ||
654 | if (!icon_theme_index_read(theme, buf)) | ||
655 | theme->valid = 0; | ||
656 | } | ||
657 | } | ||
658 | eina_iterator_free(it); | ||
659 | return EINA_TRUE; | ||
660 | } | ||
661 | |||
662 | static int | ||
663 | cache_lock_file(void) | ||
664 | { | ||
665 | char file[PATH_MAX]; | ||
666 | struct flock fl; | ||
667 | int lockfd; | ||
668 | |||
669 | snprintf(file, sizeof(file), "%s/efreet/icon_data.lock", efreet_cache_home_get()); | ||
670 | lockfd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | ||
671 | if (lockfd < 0) return -1; | ||
672 | efreet_fsetowner(lockfd); | ||
673 | |||
674 | memset(&fl, 0, sizeof(struct flock)); | ||
675 | fl.l_type = F_WRLCK; | ||
676 | fl.l_whence = SEEK_SET; | ||
677 | if (fcntl(lockfd, F_SETLK, &fl) < 0) | ||
678 | { | ||
679 | WRN("LOCKED! You may want to delete %s if this persists", file); | ||
680 | close(lockfd); | ||
681 | return -1; | ||
682 | } | ||
683 | |||
684 | return lockfd; | ||
685 | } | ||
686 | |||
687 | static void | ||
688 | icon_theme_free(Efreet_Cache_Icon_Theme *theme) | ||
689 | { | ||
690 | void *data; | ||
691 | |||
692 | eina_list_free(theme->theme.paths); | ||
693 | eina_list_free(theme->theme.inherits); | ||
694 | EINA_LIST_FREE(theme->theme.directories, data) | ||
695 | free(data); | ||
696 | if (theme->dirs) efreet_hash_free(theme->dirs, free); | ||
697 | free(theme); | ||
698 | } | ||
699 | |||
700 | int | ||
701 | main(int argc, char **argv) | ||
702 | { | ||
703 | /* TODO: | ||
704 | * - Add file monitor on files, so that we catch changes on files | ||
705 | * during whilst this program runs. | ||
706 | * - Maybe linger for a while to reduce number of cache re-creates. | ||
707 | */ | ||
708 | Eina_Iterator *it; | ||
709 | Efreet_Cache_Version *icon_version; | ||
710 | Efreet_Cache_Version *theme_version; | ||
711 | Efreet_Cache_Icon_Theme *theme; | ||
712 | Eet_Data_Descriptor *theme_edd; | ||
713 | Eet_Data_Descriptor *icon_edd; | ||
714 | Eet_Data_Descriptor *fallback_edd; | ||
715 | Eet_File *icon_ef; | ||
716 | Eet_File *theme_ef; | ||
717 | Eina_List *xdg_dirs = NULL; | ||
718 | Eina_List *l = NULL; | ||
719 | char file[PATH_MAX]; | ||
720 | const char *path; | ||
721 | char *dir = NULL; | ||
722 | Eina_Bool changed = EINA_FALSE; | ||
723 | Eina_Bool flush = EINA_FALSE; | ||
724 | int lockfd = -1; | ||
725 | char **keys; | ||
726 | int num, i; | ||
727 | |||
728 | /* init external subsystems */ | ||
729 | if (!eina_init()) return -1; | ||
730 | _efreet_icon_cache_log_dom = | ||
731 | eina_log_domain_register("efreet_icon_cache", EFREET_DEFAULT_LOG_COLOR); | ||
732 | if (_efreet_icon_cache_log_dom < 0) | ||
733 | { | ||
734 | EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_icon_cache."); | ||
735 | return -1; | ||
736 | } | ||
737 | |||
738 | eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_ERR); | ||
739 | |||
740 | exts = eina_array_new(10); | ||
741 | extra_dirs = eina_array_new(10); | ||
742 | |||
743 | for (i = 1; i < argc; i++) | ||
744 | { | ||
745 | if (!strcmp(argv[i], "-v")) | ||
746 | eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_DBG); | ||
747 | else if ((!strcmp(argv[i], "-h")) || | ||
748 | (!strcmp(argv[i], "-help")) || | ||
749 | (!strcmp(argv[i], "--h")) || | ||
750 | (!strcmp(argv[i], "--help"))) | ||
751 | { | ||
752 | printf("Options:\n"); | ||
753 | printf(" -v Verbose mode\n"); | ||
754 | printf(" -e .ext1 .ext2 Extensions\n"); | ||
755 | printf(" -d dir1 dir2 Extra dirs\n"); | ||
756 | printf(" -f Flush\n"); | ||
757 | exit(0); | ||
758 | } | ||
759 | else if (!strcmp(argv[i], "-e")) | ||
760 | { | ||
761 | while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-')) | ||
762 | eina_array_push(exts, argv[++i]); | ||
763 | } | ||
764 | else if (!strcmp(argv[i], "-d")) | ||
765 | { | ||
766 | while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-')) | ||
767 | eina_array_push(extra_dirs, argv[++i]); | ||
768 | } | ||
769 | else if (!strcmp(argv[i], "-d")) | ||
770 | flush = EINA_TRUE; | ||
771 | } | ||
772 | |||
773 | if (!eet_init()) return -1; | ||
774 | if (!ecore_init()) return -1; | ||
775 | |||
776 | efreet_cache_update = 0; | ||
777 | /* finish efreet init */ | ||
778 | if (!efreet_init()) goto on_error; | ||
779 | |||
780 | strs = eina_array_new(32); | ||
781 | |||
782 | /* create homedir */ | ||
783 | snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get()); | ||
784 | if (!ecore_file_exists(file)) | ||
785 | { | ||
786 | if (!ecore_file_mkpath(file)) return -1; | ||
787 | efreet_setowner(file); | ||
788 | } | ||
789 | |||
790 | /* lock process, so that we only run one copy of this program */ | ||
791 | lockfd = cache_lock_file(); | ||
792 | if (lockfd == -1) goto on_error; | ||
793 | |||
794 | /* Need to init edd's, so they are like we want, not like userspace wants */ | ||
795 | icon_edd = efreet_icon_edd(); | ||
796 | fallback_edd = efreet_icon_fallback_edd(); | ||
797 | theme_edd = efreet_icon_theme_edd(EINA_TRUE); | ||
798 | |||
799 | icon_themes = eina_hash_string_superfast_new(EINA_FREE_CB(icon_theme_free)); | ||
800 | |||
801 | INF("opening theme cache"); | ||
802 | /* open theme file */ | ||
803 | theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE); | ||
804 | if (!theme_ef) goto on_error_efreet; | ||
805 | theme_version = eet_data_read(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION); | ||
806 | if (theme_version && | ||
807 | ((theme_version->major != EFREET_ICON_CACHE_MAJOR) || | ||
808 | (theme_version->minor != EFREET_ICON_CACHE_MINOR))) | ||
809 | { | ||
810 | // delete old cache | ||
811 | eet_close(theme_ef); | ||
812 | if (unlink(efreet_icon_theme_cache_file()) < 0) | ||
813 | { | ||
814 | if (errno != ENOENT) goto on_error_efreet; | ||
815 | } | ||
816 | theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE); | ||
817 | if (!theme_ef) goto on_error_efreet; | ||
818 | } | ||
819 | if (!theme_version) | ||
820 | theme_version = NEW(Efreet_Cache_Version, 1); | ||
821 | |||
822 | theme_version->major = EFREET_ICON_CACHE_MAJOR; | ||
823 | theme_version->minor = EFREET_ICON_CACHE_MINOR; | ||
824 | |||
825 | if (flush) | ||
826 | changed = EINA_TRUE; | ||
827 | |||
828 | if (exts->count == 0) | ||
829 | { | ||
830 | ERR("Need to pass extensions to icon cache create process"); | ||
831 | goto on_error_efreet; | ||
832 | } | ||
833 | |||
834 | keys = eet_list(theme_ef, "*", &num); | ||
835 | if (keys) | ||
836 | { | ||
837 | for (i = 0; i < num; i++) | ||
838 | { | ||
839 | if (!strncmp(keys[i], "__efreet", 8)) continue; | ||
840 | theme = eet_data_read(theme_ef, theme_edd, keys[i]); | ||
841 | if (theme) | ||
842 | { | ||
843 | theme->valid = 0; | ||
844 | eina_hash_direct_add(icon_themes, theme->theme.name.internal, theme); | ||
845 | } | ||
846 | } | ||
847 | free(keys); | ||
848 | } | ||
849 | |||
850 | INF("scan for themes"); | ||
851 | /* scan themes */ | ||
852 | cache_theme_scan(efreet_icon_deprecated_user_dir_get()); | ||
853 | cache_theme_scan(efreet_icon_user_dir_get()); | ||
854 | |||
855 | xdg_dirs = efreet_data_dirs_get(); | ||
856 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
857 | { | ||
858 | snprintf(file, sizeof(file), "%s/icons", dir); | ||
859 | cache_theme_scan(file); | ||
860 | } | ||
861 | |||
862 | #ifndef STRICT_SPEC | ||
863 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
864 | { | ||
865 | snprintf(file, sizeof(file), "%s/pixmaps", dir); | ||
866 | cache_theme_scan(file); | ||
867 | } | ||
868 | #endif | ||
869 | |||
870 | cache_theme_scan("/usr/share/pixmaps"); | ||
871 | |||
872 | /* scan icons */ | ||
873 | it = eina_hash_iterator_data_new(icon_themes); | ||
874 | EINA_ITERATOR_FOREACH(it, theme) | ||
875 | { | ||
876 | if (!theme->valid) continue; | ||
877 | #ifndef STRICT_SPEC | ||
878 | if (!theme->theme.name.name) continue; | ||
879 | #endif | ||
880 | INF("scan theme %s", theme->theme.name.name); | ||
881 | |||
882 | theme->changed = check_changed(theme); | ||
883 | if (flush) | ||
884 | theme->changed = EINA_TRUE; | ||
885 | |||
886 | INF("open icon file"); | ||
887 | /* open icon file */ | ||
888 | icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE); | ||
889 | if (!icon_ef) goto on_error_efreet; | ||
890 | icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION); | ||
891 | if (theme->changed || (icon_version && | ||
892 | ((icon_version->major != EFREET_ICON_CACHE_MAJOR) || | ||
893 | (icon_version->minor != EFREET_ICON_CACHE_MINOR)))) | ||
894 | { | ||
895 | // delete old cache | ||
896 | eet_close(icon_ef); | ||
897 | if (unlink(efreet_icon_cache_file(theme->theme.name.internal)) < 0) | ||
898 | { | ||
899 | if (errno != ENOENT) goto on_error_efreet; | ||
900 | } | ||
901 | icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE); | ||
902 | if (!icon_ef) goto on_error_efreet; | ||
903 | theme->changed = EINA_TRUE; | ||
904 | } | ||
905 | |||
906 | if (theme->changed) | ||
907 | changed = EINA_TRUE; | ||
908 | |||
909 | if (!icon_version) | ||
910 | icon_version = NEW(Efreet_Cache_Version, 1); | ||
911 | |||
912 | icon_version->major = EFREET_ICON_CACHE_MAJOR; | ||
913 | icon_version->minor = EFREET_ICON_CACHE_MINOR; | ||
914 | |||
915 | if (theme->changed) | ||
916 | { | ||
917 | Eina_Hash *themes; | ||
918 | Eina_Hash *icons; | ||
919 | |||
920 | themes = eina_hash_string_superfast_new(NULL); | ||
921 | icons = eina_hash_string_superfast_new(NULL); | ||
922 | |||
923 | INF("scan icons\n"); | ||
924 | if (cache_scan(&(theme->theme), themes, icons)) | ||
925 | { | ||
926 | Eina_Iterator *icons_it; | ||
927 | Eina_Hash_Tuple *tuple; | ||
928 | |||
929 | INF("generated: '%s' %i (%i)", | ||
930 | theme->theme.name.internal, | ||
931 | theme->changed, | ||
932 | eina_hash_population(icons)); | ||
933 | |||
934 | icons_it = eina_hash_iterator_tuple_new(icons); | ||
935 | EINA_ITERATOR_FOREACH(icons_it, tuple) | ||
936 | eet_data_write(icon_ef, icon_edd, tuple->key, tuple->data, 1); | ||
937 | eina_iterator_free(icons_it); | ||
938 | |||
939 | INF("theme change: %s %lld", theme->theme.name.internal, theme->last_cache_check); | ||
940 | eet_data_write(theme_ef, theme_edd, theme->theme.name.internal, theme, 1); | ||
941 | } | ||
942 | eina_hash_free(themes); | ||
943 | eina_hash_free(icons); | ||
944 | changed = EINA_TRUE; | ||
945 | } | ||
946 | |||
947 | eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, 1); | ||
948 | eet_close(icon_ef); | ||
949 | efreet_setowner(efreet_icon_cache_file(theme->theme.name.internal)); | ||
950 | free(icon_version); | ||
951 | } | ||
952 | eina_iterator_free(it); | ||
953 | |||
954 | INF("scan fallback icons"); | ||
955 | theme = eet_data_read(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK); | ||
956 | if (!theme) | ||
957 | { | ||
958 | theme = NEW(Efreet_Cache_Icon_Theme, 1); | ||
959 | theme->changed = EINA_TRUE; | ||
960 | } | ||
961 | if (flush) | ||
962 | theme->changed = EINA_TRUE; | ||
963 | |||
964 | INF("open fallback file"); | ||
965 | /* open icon file */ | ||
966 | icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE); | ||
967 | if (!icon_ef) goto on_error_efreet; | ||
968 | icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION); | ||
969 | if (theme->changed || (icon_version && | ||
970 | ((icon_version->major != EFREET_ICON_CACHE_MAJOR) || | ||
971 | (icon_version->minor != EFREET_ICON_CACHE_MINOR)))) | ||
972 | { | ||
973 | // delete old cache | ||
974 | eet_close(icon_ef); | ||
975 | if (unlink(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)) < 0) | ||
976 | { | ||
977 | if (errno != ENOENT) goto on_error_efreet; | ||
978 | } | ||
979 | icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE); | ||
980 | if (!icon_ef) goto on_error_efreet; | ||
981 | theme->changed = EINA_TRUE; | ||
982 | } | ||
983 | if (!theme->changed) | ||
984 | theme->changed = check_fallback_changed(theme); | ||
985 | if (theme->changed && theme->dirs) | ||
986 | { | ||
987 | efreet_hash_free(theme->dirs, free); | ||
988 | theme->dirs = NULL; | ||
989 | } | ||
990 | if (!theme->dirs) | ||
991 | theme->dirs = eina_hash_string_superfast_new(NULL); | ||
992 | |||
993 | if (theme->changed) | ||
994 | changed = EINA_TRUE; | ||
995 | |||
996 | if (!icon_version) | ||
997 | icon_version = NEW(Efreet_Cache_Version, 1); | ||
998 | |||
999 | icon_version->major = EFREET_ICON_CACHE_MAJOR; | ||
1000 | icon_version->minor = EFREET_ICON_CACHE_MINOR; | ||
1001 | |||
1002 | if (theme->changed) | ||
1003 | { | ||
1004 | Eina_Hash *icons; | ||
1005 | |||
1006 | icons = eina_hash_string_superfast_new(NULL); | ||
1007 | |||
1008 | INF("scan fallback icons"); | ||
1009 | /* Save fallback in the right part */ | ||
1010 | if (cache_fallback_scan(icons, theme->dirs)) | ||
1011 | { | ||
1012 | Eina_Iterator *icons_it; | ||
1013 | Eina_Hash_Tuple *tuple; | ||
1014 | |||
1015 | INF("generated: fallback %i (%i)", theme->changed, eina_hash_population(icons)); | ||
1016 | |||
1017 | icons_it = eina_hash_iterator_tuple_new(icons); | ||
1018 | EINA_ITERATOR_FOREACH(icons_it, tuple) | ||
1019 | eet_data_write(icon_ef, fallback_edd, tuple->key, tuple->data, 1); | ||
1020 | eina_iterator_free(icons_it); | ||
1021 | } | ||
1022 | eina_hash_free(icons); | ||
1023 | |||
1024 | eet_data_write(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK, theme, 1); | ||
1025 | } | ||
1026 | |||
1027 | icon_theme_free(theme); | ||
1028 | |||
1029 | eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, 1); | ||
1030 | eet_close(icon_ef); | ||
1031 | efreet_setowner(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)); | ||
1032 | free(icon_version); | ||
1033 | |||
1034 | eina_hash_free(icon_themes); | ||
1035 | |||
1036 | /* save data */ | ||
1037 | eet_data_write(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION, theme_version, 1); | ||
1038 | |||
1039 | eet_close(theme_ef); | ||
1040 | efreet_setowner(efreet_icon_theme_cache_file()); | ||
1041 | free(theme_version); | ||
1042 | |||
1043 | { | ||
1044 | char c = 'n'; | ||
1045 | |||
1046 | if (changed) c = 'c'; | ||
1047 | printf("%c\n", c); | ||
1048 | } | ||
1049 | |||
1050 | INF("done"); | ||
1051 | on_error_efreet: | ||
1052 | efreet_shutdown(); | ||
1053 | if (theme_ef) eet_close(theme_ef); | ||
1054 | |||
1055 | on_error: | ||
1056 | if (lockfd >= 0) close(lockfd); | ||
1057 | |||
1058 | while ((path = eina_array_pop(strs))) | ||
1059 | eina_stringshare_del(path); | ||
1060 | eina_array_free(strs); | ||
1061 | eina_array_free(exts); | ||
1062 | eina_array_free(extra_dirs); | ||
1063 | |||
1064 | ecore_shutdown(); | ||
1065 | eet_shutdown(); | ||
1066 | eina_log_domain_unregister(_efreet_icon_cache_log_dom); | ||
1067 | eina_shutdown(); | ||
1068 | |||
1069 | return 0; | ||
1070 | } | ||
diff --git a/src/bin/efreet/efreetd.c b/src/bin/efreet/efreetd.c new file mode 100644 index 0000000000..a4ae720a4e --- /dev/null +++ b/src/bin/efreet/efreetd.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <Ecore.h> | ||
6 | #include <Ecore_File.h> | ||
7 | |||
8 | #include "efreetd.h" | ||
9 | #include "efreetd_dbus.h" | ||
10 | #include "efreetd_cache.h" | ||
11 | |||
12 | int efreetd_log_dom = -1; | ||
13 | |||
14 | void | ||
15 | quit(void) | ||
16 | { | ||
17 | ecore_main_loop_quit(); | ||
18 | } | ||
19 | |||
20 | int | ||
21 | main(void) | ||
22 | { | ||
23 | if (!eina_init()) return 1; | ||
24 | efreetd_log_dom = eina_log_domain_register("efreetd", EFREETD_DEFAULT_LOG_COLOR); | ||
25 | if (efreetd_log_dom < 0) | ||
26 | { | ||
27 | EINA_LOG_ERR("Efreet: Could not create a log domain for efreetd."); | ||
28 | goto ecore_error; | ||
29 | } | ||
30 | if (!ecore_init()) goto ecore_error; | ||
31 | if (!ecore_file_init()) goto ecore_file_error; | ||
32 | |||
33 | if (!dbus_init()) goto dbus_error; | ||
34 | if (!cache_init()) goto cache_error; | ||
35 | |||
36 | ecore_main_loop_begin(); | ||
37 | |||
38 | cache_shutdown(); | ||
39 | dbus_shutdown(); | ||
40 | ecore_file_shutdown(); | ||
41 | ecore_shutdown(); | ||
42 | eina_log_domain_unregister(efreetd_log_dom); | ||
43 | efreetd_log_dom = -1; | ||
44 | eina_shutdown(); | ||
45 | return 0; | ||
46 | |||
47 | cache_error: | ||
48 | dbus_shutdown(); | ||
49 | dbus_error: | ||
50 | ecore_file_shutdown(); | ||
51 | ecore_file_error: | ||
52 | ecore_shutdown(); | ||
53 | ecore_error: | ||
54 | if (efreetd_log_dom >= 0) | ||
55 | eina_log_domain_unregister(efreetd_log_dom); | ||
56 | efreetd_log_dom = -1; | ||
57 | eina_shutdown(); | ||
58 | return 1; | ||
59 | } | ||
diff --git a/src/bin/efreet/efreetd.h b/src/bin/efreet/efreetd.h new file mode 100644 index 0000000000..a6931e3282 --- /dev/null +++ b/src/bin/efreet/efreetd.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef __EFREETD_H | ||
2 | #define __EFREETD_H | ||
3 | |||
4 | #ifdef EFREETD_DEFAULT_LOG_COLOR | ||
5 | #undef EFREETD_DEFAULT_LOG_COLOR | ||
6 | #endif | ||
7 | #define EFREETD_DEFAULT_LOG_COLOR "\033[36m" | ||
8 | |||
9 | extern int efreetd_log_dom; | ||
10 | |||
11 | #ifdef CRITICAL | ||
12 | #undef CRITICAL | ||
13 | #endif | ||
14 | #define CRITICAL(...) EINA_LOG_DOM_CRIT(efreetd_log_dom, __VA_ARGS__) | ||
15 | #ifdef ERR | ||
16 | #undef ERR | ||
17 | #endif | ||
18 | #define ERR(...) EINA_LOG_DOM_ERR(efreetd_log_dom, __VA_ARGS__) | ||
19 | #ifdef DBG | ||
20 | #undef DBG | ||
21 | #endif | ||
22 | #define DBG(...) EINA_LOG_DOM_DBG(efreetd_log_dom, __VA_ARGS__) | ||
23 | #ifdef INF | ||
24 | #undef INF | ||
25 | #endif | ||
26 | #define INF(...) EINA_LOG_DOM_INFO(efreetd_log_dom, __VA_ARGS__) | ||
27 | #ifdef WRN | ||
28 | #undef WRN | ||
29 | #endif | ||
30 | #define WRN(...) EINA_LOG_DOM_WARN(efreetd_log_dom, __VA_ARGS__) | ||
31 | |||
32 | void quit(void); | ||
33 | |||
34 | #endif | ||
diff --git a/src/bin/efreet/efreetd_cache.c b/src/bin/efreet/efreetd_cache.c new file mode 100644 index 0000000000..5af928bde0 --- /dev/null +++ b/src/bin/efreet/efreetd_cache.c | |||
@@ -0,0 +1,575 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <Eina.h> | ||
6 | #include <Ecore.h> | ||
7 | #include <Ecore_File.h> | ||
8 | |||
9 | #include "efreetd.h" | ||
10 | #include "efreetd_dbus.h" | ||
11 | |||
12 | #include "Efreet.h" | ||
13 | #define EFREET_MODULE_LOG_DOM efreetd_log_dom | ||
14 | #include "efreet_private.h" | ||
15 | #include "efreetd_cache.h" | ||
16 | |||
17 | static Eina_Hash *change_monitors = NULL; | ||
18 | |||
19 | static Ecore_Event_Handler *cache_exe_del_handler = NULL; | ||
20 | static Ecore_Event_Handler *cache_exe_data_handler = NULL; | ||
21 | static Ecore_Exe *icon_cache_exe = NULL; | ||
22 | static Ecore_Exe *desktop_cache_exe = NULL; | ||
23 | static Ecore_Timer *icon_cache_timer = NULL; | ||
24 | static Ecore_Timer *desktop_cache_timer = NULL; | ||
25 | |||
26 | static Eina_Bool desktop_exists = EINA_FALSE; | ||
27 | |||
28 | static Eina_List *desktop_system_dirs = NULL; | ||
29 | static Eina_List *desktop_extra_dirs = NULL; | ||
30 | static Eina_List *icon_extra_dirs = NULL; | ||
31 | static Eina_List *icon_exts = NULL; | ||
32 | static Eina_Bool icon_flush = EINA_FALSE; | ||
33 | |||
34 | static Eina_Bool desktop_queue = EINA_FALSE; | ||
35 | static Eina_Bool icon_queue = EINA_FALSE; | ||
36 | |||
37 | static void desktop_changes_monitor_add(const char *path); | ||
38 | |||
39 | /* internal */ | ||
40 | static Eina_Bool | ||
41 | icon_cache_update_cache_cb(void *data EINA_UNUSED) | ||
42 | { | ||
43 | char file[PATH_MAX]; | ||
44 | int prio; | ||
45 | |||
46 | icon_cache_timer = NULL; | ||
47 | |||
48 | if (icon_cache_exe) | ||
49 | { | ||
50 | icon_queue = EINA_TRUE; | ||
51 | return ECORE_CALLBACK_CANCEL; | ||
52 | } | ||
53 | icon_queue = EINA_FALSE; | ||
54 | if ((!icon_flush) && (!icon_exts)) return ECORE_CALLBACK_CANCEL; | ||
55 | |||
56 | /* TODO: Queue if already running */ | ||
57 | prio = ecore_exe_run_priority_get(); | ||
58 | ecore_exe_run_priority_set(19); | ||
59 | // XXX: use eina_prefix, not hard-coded prefixes | ||
60 | eina_strlcpy(file, PACKAGE_LIB_DIR "/efreet/efreet_icon_cache_create", sizeof(file)); | ||
61 | if (icon_extra_dirs) | ||
62 | { | ||
63 | Eina_List *ll; | ||
64 | char *p; | ||
65 | |||
66 | eina_strlcat(file, " -d", sizeof(file)); | ||
67 | EINA_LIST_FOREACH(icon_extra_dirs, ll, p) | ||
68 | { | ||
69 | eina_strlcat(file, " ", sizeof(file)); | ||
70 | eina_strlcat(file, p, sizeof(file)); | ||
71 | } | ||
72 | } | ||
73 | if (icon_exts) | ||
74 | { | ||
75 | Eina_List *ll; | ||
76 | char *p; | ||
77 | |||
78 | eina_strlcat(file, " -e", sizeof(file)); | ||
79 | EINA_LIST_FOREACH(icon_exts, ll, p) | ||
80 | { | ||
81 | eina_strlcat(file, " ", sizeof(file)); | ||
82 | eina_strlcat(file, p, sizeof(file)); | ||
83 | } | ||
84 | } | ||
85 | if (icon_flush) | ||
86 | eina_strlcat(file, " -f", sizeof(file)); | ||
87 | icon_flush = EINA_FALSE; | ||
88 | icon_cache_exe = | ||
89 | ecore_exe_pipe_run(file, ECORE_EXE_PIPE_READ|ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); | ||
90 | ecore_exe_run_priority_set(prio); | ||
91 | |||
92 | return ECORE_CALLBACK_CANCEL; | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | cache_icon_update(Eina_Bool flush) | ||
97 | { | ||
98 | if (icon_cache_timer) | ||
99 | ecore_timer_del(icon_cache_timer); | ||
100 | if (flush) | ||
101 | icon_flush = flush; | ||
102 | icon_cache_timer = ecore_timer_add(1.0, icon_cache_update_cache_cb, NULL); | ||
103 | } | ||
104 | |||
105 | static Eina_Bool | ||
106 | desktop_cache_update_cache_cb(void *data EINA_UNUSED) | ||
107 | { | ||
108 | char file[PATH_MAX]; | ||
109 | int prio; | ||
110 | |||
111 | desktop_cache_timer = NULL; | ||
112 | |||
113 | if (desktop_cache_exe) | ||
114 | { | ||
115 | desktop_queue = EINA_TRUE; | ||
116 | return ECORE_CALLBACK_CANCEL; | ||
117 | } | ||
118 | desktop_queue = EINA_FALSE; | ||
119 | prio = ecore_exe_run_priority_get(); | ||
120 | ecore_exe_run_priority_set(19); | ||
121 | // XXX: use eina_prefix, not hard-coded prefixes | ||
122 | eina_strlcpy(file, PACKAGE_LIB_DIR "/efreet/efreet_desktop_cache_create", sizeof(file)); | ||
123 | if (desktop_extra_dirs) | ||
124 | { | ||
125 | Eina_List *ll; | ||
126 | const char *str; | ||
127 | |||
128 | eina_strlcat(file, " -d", sizeof(file)); | ||
129 | EINA_LIST_FOREACH(desktop_extra_dirs, ll, str) | ||
130 | { | ||
131 | eina_strlcat(file, " ", sizeof(file)); | ||
132 | eina_strlcat(file, str, sizeof(file)); | ||
133 | } | ||
134 | } | ||
135 | INF("Run desktop cache creation: %s", file); | ||
136 | desktop_cache_exe = | ||
137 | ecore_exe_pipe_run(file, ECORE_EXE_PIPE_READ|ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); | ||
138 | ecore_exe_run_priority_set(prio); | ||
139 | |||
140 | return ECORE_CALLBACK_CANCEL; | ||
141 | } | ||
142 | |||
143 | static Eina_Bool | ||
144 | cache_exe_data_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) | ||
145 | { | ||
146 | Ecore_Exe_Event_Data *ev; | ||
147 | |||
148 | ev = event; | ||
149 | if (ev->exe == desktop_cache_exe) | ||
150 | { | ||
151 | Eina_Bool update = EINA_FALSE; | ||
152 | |||
153 | if ((ev->lines) && (*ev->lines->line == 'c')) | ||
154 | update = EINA_TRUE; | ||
155 | |||
156 | desktop_exists = EINA_TRUE; | ||
157 | send_signal_desktop_cache_update(update); | ||
158 | } | ||
159 | else if (ev->exe == icon_cache_exe) | ||
160 | { | ||
161 | Eina_Bool update = EINA_FALSE; | ||
162 | |||
163 | if ((ev->lines) && (*ev->lines->line == 'c')) | ||
164 | update = EINA_TRUE; | ||
165 | |||
166 | send_signal_icon_cache_update(update); | ||
167 | } | ||
168 | return ECORE_CALLBACK_RENEW; | ||
169 | } | ||
170 | |||
171 | static Eina_Bool | ||
172 | cache_exe_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) | ||
173 | { | ||
174 | Ecore_Exe_Event_Del *ev; | ||
175 | |||
176 | ev = event; | ||
177 | if (ev->exe == desktop_cache_exe) | ||
178 | { | ||
179 | desktop_cache_exe = NULL; | ||
180 | if (desktop_queue) cache_desktop_update(); | ||
181 | } | ||
182 | else if (ev->exe == icon_cache_exe) | ||
183 | { | ||
184 | icon_cache_exe = NULL; | ||
185 | if (icon_queue) cache_icon_update(EINA_FALSE); | ||
186 | } | ||
187 | return ECORE_CALLBACK_RENEW; | ||
188 | } | ||
189 | |||
190 | static void | ||
191 | icon_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, | ||
192 | Ecore_File_Event event, const char *path) | ||
193 | { | ||
194 | /* TODO: If we get a stale symlink, we need to rerun cache creation */ | ||
195 | switch (event) | ||
196 | { | ||
197 | case ECORE_FILE_EVENT_NONE: | ||
198 | /* noop */ | ||
199 | break; | ||
200 | |||
201 | case ECORE_FILE_EVENT_CREATED_FILE: | ||
202 | case ECORE_FILE_EVENT_DELETED_FILE: | ||
203 | case ECORE_FILE_EVENT_MODIFIED: | ||
204 | case ECORE_FILE_EVENT_CLOSED: | ||
205 | case ECORE_FILE_EVENT_DELETED_DIRECTORY: | ||
206 | case ECORE_FILE_EVENT_CREATED_DIRECTORY: | ||
207 | cache_icon_update(EINA_FALSE); | ||
208 | break; | ||
209 | |||
210 | case ECORE_FILE_EVENT_DELETED_SELF: | ||
211 | eina_hash_del_by_key(change_monitors, path); | ||
212 | cache_icon_update(EINA_FALSE); | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | static void | ||
218 | icon_changes_monitor_add(const char *path) | ||
219 | { | ||
220 | Ecore_File_Monitor *mon; | ||
221 | |||
222 | if (eina_hash_find(change_monitors, path)) return; | ||
223 | /* TODO: Check for symlink and monitor the real path */ | ||
224 | mon = ecore_file_monitor_add(path, | ||
225 | icon_changes_cb, | ||
226 | NULL); | ||
227 | if (mon) | ||
228 | eina_hash_add(change_monitors, path, mon); | ||
229 | } | ||
230 | |||
231 | static void | ||
232 | icon_changes_listen_recursive(const char *path, Eina_Bool base) | ||
233 | { | ||
234 | Eina_Iterator *it; | ||
235 | Eina_File_Direct_Info *info; | ||
236 | |||
237 | if ((!ecore_file_is_dir(path)) && (base)) | ||
238 | { | ||
239 | // XXX: if it doesn't exist... walk the parent dirs back down | ||
240 | // to this path until we find one that doesn't exist, then | ||
241 | // monitor its parent, and treat it specially as it needs | ||
242 | // to look for JUST the creation of this specific child | ||
243 | // and when this child is created, replace this monitor with | ||
244 | // monitoring the next specific child dir down until we are | ||
245 | // monitoring the original path again. | ||
246 | } | ||
247 | icon_changes_monitor_add(path); | ||
248 | it = eina_file_stat_ls(path); | ||
249 | if (!it) return; | ||
250 | EINA_ITERATOR_FOREACH(it, info) | ||
251 | { | ||
252 | if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) || | ||
253 | (info->type == EINA_FILE_DIR)) | ||
254 | icon_changes_monitor_add(info->path); | ||
255 | } | ||
256 | eina_iterator_free(it); | ||
257 | } | ||
258 | |||
259 | static void | ||
260 | icon_changes_listen(void) | ||
261 | { | ||
262 | Eina_List *l; | ||
263 | Eina_List *xdg_dirs; | ||
264 | char buf[PATH_MAX]; | ||
265 | const char *dir; | ||
266 | |||
267 | icon_changes_listen_recursive(efreet_icon_deprecated_user_dir_get(), EINA_TRUE); | ||
268 | icon_changes_listen_recursive(efreet_icon_user_dir_get(), EINA_TRUE); | ||
269 | EINA_LIST_FOREACH(icon_extra_dirs, l, dir) | ||
270 | { | ||
271 | icon_changes_listen_recursive(dir, EINA_TRUE); | ||
272 | } | ||
273 | |||
274 | xdg_dirs = efreet_data_dirs_get(); | ||
275 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
276 | { | ||
277 | snprintf(buf, sizeof(buf), "%s/icons", dir); | ||
278 | icon_changes_listen_recursive(buf, EINA_TRUE); | ||
279 | } | ||
280 | |||
281 | #ifndef STRICT_SPEC | ||
282 | EINA_LIST_FOREACH(xdg_dirs, l, dir) | ||
283 | { | ||
284 | snprintf(buf, sizeof(buf), "%s/pixmaps", dir); | ||
285 | icon_changes_listen_recursive(buf, EINA_TRUE); | ||
286 | } | ||
287 | #endif | ||
288 | |||
289 | icon_changes_monitor_add("/usr/share/pixmaps"); | ||
290 | } | ||
291 | |||
292 | static void | ||
293 | desktop_changes_cb(void *data EINA_UNUSED, Ecore_File_Monitor *em EINA_UNUSED, | ||
294 | Ecore_File_Event event, const char *path) | ||
295 | { | ||
296 | const char *ext; | ||
297 | |||
298 | /* TODO: If we get a stale symlink, we need to rerun cache creation */ | ||
299 | /* TODO: Check for desktop*.cache, as this will be created when app is installed */ | ||
300 | /* TODO: Do efreet_cache_icon_update() when app is installed, as it has the same | ||
301 | * symlink problem */ | ||
302 | switch (event) | ||
303 | { | ||
304 | case ECORE_FILE_EVENT_NONE: | ||
305 | /* noop */ | ||
306 | break; | ||
307 | |||
308 | case ECORE_FILE_EVENT_CREATED_FILE: | ||
309 | case ECORE_FILE_EVENT_DELETED_FILE: | ||
310 | case ECORE_FILE_EVENT_MODIFIED: | ||
311 | case ECORE_FILE_EVENT_CLOSED: | ||
312 | ext = strrchr(path, '.'); | ||
313 | if (ext && (!strcmp(ext, ".desktop") || !strcmp(ext, ".directory"))) | ||
314 | cache_desktop_update(); | ||
315 | break; | ||
316 | |||
317 | case ECORE_FILE_EVENT_DELETED_SELF: | ||
318 | case ECORE_FILE_EVENT_DELETED_DIRECTORY: | ||
319 | eina_hash_del_by_key(change_monitors, path); | ||
320 | cache_desktop_update(); | ||
321 | break; | ||
322 | |||
323 | case ECORE_FILE_EVENT_CREATED_DIRECTORY: | ||
324 | desktop_changes_monitor_add(path); | ||
325 | cache_desktop_update(); | ||
326 | break; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | static void | ||
331 | desktop_changes_monitor_add(const char *path) | ||
332 | { | ||
333 | Ecore_File_Monitor *mon; | ||
334 | |||
335 | if (eina_hash_find(change_monitors, path)) return; | ||
336 | /* TODO: Check for symlink and monitor the real path */ | ||
337 | mon = ecore_file_monitor_add(path, | ||
338 | desktop_changes_cb, | ||
339 | NULL); | ||
340 | if (mon) | ||
341 | eina_hash_add(change_monitors, path, mon); | ||
342 | } | ||
343 | |||
344 | static void | ||
345 | desktop_changes_listen_recursive(const char *path) | ||
346 | { | ||
347 | Eina_Iterator *it; | ||
348 | Eina_File_Direct_Info *info; | ||
349 | |||
350 | if (!ecore_file_is_dir(path)) return; | ||
351 | desktop_changes_monitor_add(path); | ||
352 | it = eina_file_stat_ls(path); | ||
353 | if (!it) return; | ||
354 | EINA_ITERATOR_FOREACH(it, info) | ||
355 | { | ||
356 | if (((info->type == EINA_FILE_LNK) && (ecore_file_is_dir(info->path))) || | ||
357 | (info->type == EINA_FILE_DIR)) | ||
358 | desktop_changes_listen_recursive(info->path); | ||
359 | } | ||
360 | eina_iterator_free(it); | ||
361 | } | ||
362 | |||
363 | static void | ||
364 | desktop_changes_listen(void) | ||
365 | { | ||
366 | Eina_List *l; | ||
367 | const char *path; | ||
368 | |||
369 | EINA_LIST_FOREACH(desktop_system_dirs, l, path) | ||
370 | desktop_changes_listen_recursive(path); | ||
371 | |||
372 | EINA_LIST_FOREACH(desktop_extra_dirs, l, path) | ||
373 | desktop_changes_listen_recursive(path); | ||
374 | } | ||
375 | |||
376 | static void | ||
377 | fill_list(const char *file, Eina_List **l) | ||
378 | { | ||
379 | Eina_File *f = NULL; | ||
380 | Eina_Iterator *it = NULL; | ||
381 | Eina_File_Line *line = NULL; | ||
382 | char buf[PATH_MAX]; | ||
383 | |||
384 | snprintf(buf, sizeof(buf), "%s/efreet/%s", efreet_cache_home_get(), file); | ||
385 | f = eina_file_open(buf, EINA_FALSE); | ||
386 | if (!f) return; | ||
387 | it = eina_file_map_lines(f); | ||
388 | if (!it) goto error; | ||
389 | EINA_ITERATOR_FOREACH(it, line) | ||
390 | { | ||
391 | const char *end; | ||
392 | end = line->end - 1; | ||
393 | *l = eina_list_append(*l, eina_stringshare_add_length(line->start, end - line->start)); | ||
394 | } | ||
395 | eina_iterator_free(it); | ||
396 | error: | ||
397 | eina_file_close(f); | ||
398 | } | ||
399 | |||
400 | static void | ||
401 | read_lists(void) | ||
402 | { | ||
403 | fill_list("extra_desktop.dirs", &desktop_extra_dirs); | ||
404 | fill_list("extra_icon.dirs", &icon_extra_dirs); | ||
405 | fill_list("icon.exts", &icon_exts); | ||
406 | } | ||
407 | |||
408 | static void | ||
409 | save_list(const char *file, Eina_List *l) | ||
410 | { | ||
411 | FILE *f; | ||
412 | char buf[PATH_MAX]; | ||
413 | Eina_List *ll; | ||
414 | const char *path; | ||
415 | |||
416 | snprintf(buf, sizeof(buf), "%s/efreet/%s", efreet_cache_home_get(), file); | ||
417 | f = fopen(buf, "wb"); | ||
418 | if (!f) return; | ||
419 | EINA_LIST_FOREACH(l, ll, path) | ||
420 | fprintf(f, "%s\n", path); | ||
421 | fclose(f); | ||
422 | } | ||
423 | |||
424 | static int | ||
425 | strcmplen(const void *data1, const void *data2) | ||
426 | { | ||
427 | return strncmp(data1, data2, eina_stringshare_strlen(data1)); | ||
428 | } | ||
429 | |||
430 | /* external */ | ||
431 | void | ||
432 | cache_desktop_dir_add(const char *dir) | ||
433 | { | ||
434 | char *san; | ||
435 | Eina_List *l; | ||
436 | |||
437 | san = eina_file_path_sanitize(dir); | ||
438 | if (!san) return; | ||
439 | if ((l = eina_list_search_unsorted_list(desktop_system_dirs, strcmplen, san))) | ||
440 | { | ||
441 | /* Path is registered, but maybe not monitored */ | ||
442 | const char *path = eina_list_data_get(l); | ||
443 | if (!eina_hash_find(change_monitors, path)) | ||
444 | cache_desktop_update(); | ||
445 | } | ||
446 | else if (!eina_list_search_unsorted_list(desktop_extra_dirs, EINA_COMPARE_CB(strcmp), san)) | ||
447 | { | ||
448 | /* Not a registered path */ | ||
449 | desktop_extra_dirs = eina_list_append(desktop_extra_dirs, eina_stringshare_add(san)); | ||
450 | save_list("extra_desktop.dirs", desktop_extra_dirs); | ||
451 | cache_desktop_update(); | ||
452 | } | ||
453 | free(san); | ||
454 | } | ||
455 | |||
456 | void | ||
457 | cache_icon_dir_add(const char *dir) | ||
458 | { | ||
459 | char *san; | ||
460 | |||
461 | san = eina_file_path_sanitize(dir); | ||
462 | if (!san) return; | ||
463 | if (!eina_list_search_unsorted_list(icon_extra_dirs, EINA_COMPARE_CB(strcmp), san)) | ||
464 | { | ||
465 | icon_extra_dirs = eina_list_append(icon_extra_dirs, eina_stringshare_add(san)); | ||
466 | save_list("extra_icon.dirs", icon_extra_dirs); | ||
467 | cache_icon_update(EINA_TRUE); | ||
468 | } | ||
469 | free(san); | ||
470 | } | ||
471 | |||
472 | void | ||
473 | cache_icon_ext_add(const char *ext) | ||
474 | { | ||
475 | if (!eina_list_search_unsorted_list(icon_exts, EINA_COMPARE_CB(strcmp), ext)) | ||
476 | { | ||
477 | icon_exts = eina_list_append(icon_exts, eina_stringshare_add(ext)); | ||
478 | save_list("icon.exts", icon_exts); | ||
479 | cache_icon_update(EINA_TRUE); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | void | ||
484 | cache_desktop_update(void) | ||
485 | { | ||
486 | if (desktop_cache_timer) | ||
487 | ecore_timer_del(desktop_cache_timer); | ||
488 | desktop_cache_timer = ecore_timer_add(1.0, desktop_cache_update_cache_cb, NULL); | ||
489 | } | ||
490 | |||
491 | Eina_Bool | ||
492 | cache_desktop_exists(void) | ||
493 | { | ||
494 | return desktop_exists; | ||
495 | } | ||
496 | |||
497 | Eina_Bool | ||
498 | cache_init(void) | ||
499 | { | ||
500 | char buf[PATH_MAX]; | ||
501 | |||
502 | snprintf(buf, sizeof(buf), "%s/efreet", efreet_cache_home_get()); | ||
503 | if (!ecore_file_mkpath(buf)) | ||
504 | { | ||
505 | ERR("Failed to create directory '%s'", buf); | ||
506 | goto error; | ||
507 | } | ||
508 | |||
509 | cache_exe_del_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, | ||
510 | cache_exe_del_cb, NULL); | ||
511 | if (!cache_exe_del_handler) | ||
512 | { | ||
513 | ERR("Failed to add exe del handler"); | ||
514 | goto error; | ||
515 | } | ||
516 | cache_exe_data_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DATA, | ||
517 | cache_exe_data_cb, NULL); | ||
518 | if (!cache_exe_data_handler) | ||
519 | { | ||
520 | ERR("Failed to add exe data handler"); | ||
521 | goto error; | ||
522 | } | ||
523 | |||
524 | change_monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del)); | ||
525 | |||
526 | efreet_cache_update = 0; | ||
527 | if (!efreet_init()) goto error; | ||
528 | |||
529 | read_lists(); | ||
530 | /* TODO: Should check if system dirs has changed and handles extra_dirs */ | ||
531 | desktop_system_dirs = efreet_default_dirs_get(efreet_data_home_get(), | ||
532 | efreet_data_dirs_get(), "applications"); | ||
533 | desktop_system_dirs = | ||
534 | eina_list_merge( | ||
535 | desktop_system_dirs, efreet_default_dirs_get(efreet_data_home_get(), | ||
536 | efreet_data_dirs_get(), "desktop-directories")); | ||
537 | icon_changes_listen(); | ||
538 | desktop_changes_listen(); | ||
539 | cache_icon_update(EINA_FALSE); | ||
540 | cache_desktop_update(); | ||
541 | |||
542 | return EINA_TRUE; | ||
543 | error: | ||
544 | if (cache_exe_del_handler) ecore_event_handler_del(cache_exe_del_handler); | ||
545 | cache_exe_del_handler = NULL; | ||
546 | if (cache_exe_data_handler) ecore_event_handler_del(cache_exe_data_handler); | ||
547 | cache_exe_data_handler = NULL; | ||
548 | return EINA_FALSE; | ||
549 | } | ||
550 | |||
551 | Eina_Bool | ||
552 | cache_shutdown(void) | ||
553 | { | ||
554 | const char *data; | ||
555 | |||
556 | efreet_shutdown(); | ||
557 | |||
558 | if (cache_exe_del_handler) ecore_event_handler_del(cache_exe_del_handler); | ||
559 | cache_exe_del_handler = NULL; | ||
560 | if (cache_exe_data_handler) ecore_event_handler_del(cache_exe_data_handler); | ||
561 | cache_exe_data_handler = NULL; | ||
562 | |||
563 | if (change_monitors) | ||
564 | eina_hash_free(change_monitors); | ||
565 | change_monitors = NULL; | ||
566 | EINA_LIST_FREE(desktop_system_dirs, data) | ||
567 | eina_stringshare_del(data); | ||
568 | EINA_LIST_FREE(desktop_extra_dirs, data) | ||
569 | eina_stringshare_del(data); | ||
570 | EINA_LIST_FREE(icon_extra_dirs, data) | ||
571 | eina_stringshare_del(data); | ||
572 | EINA_LIST_FREE(icon_exts, data) | ||
573 | eina_stringshare_del(data); | ||
574 | return EINA_TRUE; | ||
575 | } | ||
diff --git a/src/bin/efreet/efreetd_cache.h b/src/bin/efreet/efreetd_cache.h new file mode 100644 index 0000000000..2fb520e384 --- /dev/null +++ b/src/bin/efreet/efreetd_cache.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef __EFREETD_CACHE_H | ||
2 | #define __EFREETD_CACHE_H | ||
3 | |||
4 | void cache_desktop_dir_add(const char *dir); | ||
5 | void cache_icon_dir_add(const char *dir); | ||
6 | void cache_icon_ext_add(const char *ext); | ||
7 | void cache_desktop_update(void); | ||
8 | Eina_Bool cache_desktop_exists(void); | ||
9 | |||
10 | Eina_Bool cache_init(void); | ||
11 | Eina_Bool cache_shutdown(void); | ||
12 | |||
13 | #endif | ||
diff --git a/src/bin/efreet/efreetd_dbus.c b/src/bin/efreet/efreetd_dbus.c new file mode 100644 index 0000000000..b5e98ad083 --- /dev/null +++ b/src/bin/efreet/efreetd_dbus.c | |||
@@ -0,0 +1,262 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <Ecore.h> | ||
6 | #include <EDBus.h> | ||
7 | |||
8 | #include "efreetd.h" | ||
9 | #include "efreetd_cache.h" | ||
10 | |||
11 | #define BUS "org.enlightenment.Efreet" | ||
12 | #define PATH "/org/enlightenment/Efreet" | ||
13 | #define INTERFACE "org.enlightenment.Efreet" | ||
14 | |||
15 | /* internal */ | ||
16 | enum | ||
17 | { | ||
18 | EFREET_SIGNAL_ICON_CACHE_UPDATE = 0, | ||
19 | EFREET_SIGNAL_DESKTOP_CACHE_UPDATE | ||
20 | }; | ||
21 | |||
22 | static EDBus_Connection *conn; | ||
23 | static EDBus_Service_Interface *iface; | ||
24 | |||
25 | static Ecore_Timer *shutdown = NULL; | ||
26 | static int clients = 0; | ||
27 | |||
28 | static Eina_Bool | ||
29 | do_shutdown(void *data EINA_UNUSED) | ||
30 | { | ||
31 | quit(); | ||
32 | return ECORE_CALLBACK_CANCEL; | ||
33 | } | ||
34 | |||
35 | static void | ||
36 | disconnected(void *context EINA_UNUSED, EDBus_Connection *connection EINA_UNUSED, void *event_info EINA_UNUSED) | ||
37 | { | ||
38 | INF("disconnected"); | ||
39 | quit(); | ||
40 | } | ||
41 | |||
42 | static void | ||
43 | client_name_owner_changed_cb(void *data, const char *bus, const char *old_id, const char *new_id) | ||
44 | { | ||
45 | if (new_id[0]) | ||
46 | return; | ||
47 | edbus_name_owner_changed_callback_del(conn, bus, | ||
48 | client_name_owner_changed_cb, NULL); | ||
49 | clients--; | ||
50 | if (clients <= 0) | ||
51 | { | ||
52 | clients = 0; | ||
53 | if (shutdown) ecore_timer_del(shutdown); | ||
54 | shutdown = ecore_timer_add(10.0, do_shutdown, NULL); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | static EDBus_Message * | ||
59 | do_register(const EDBus_Service_Interface *ifc EINA_UNUSED, const EDBus_Message *message) | ||
60 | { | ||
61 | EDBus_Message *reply; | ||
62 | const char *lang; | ||
63 | |||
64 | if (!edbus_message_arguments_get(message, "s", &lang)) | ||
65 | { | ||
66 | ERR("Error getting arguments."); | ||
67 | return NULL; | ||
68 | } | ||
69 | setenv("LANG", lang, 1); | ||
70 | |||
71 | clients++; | ||
72 | if (shutdown) ecore_timer_del(shutdown); | ||
73 | shutdown = NULL; | ||
74 | |||
75 | edbus_name_owner_changed_callback_add(conn, | ||
76 | edbus_message_sender_get(message), | ||
77 | client_name_owner_changed_cb, NULL, | ||
78 | EINA_FALSE); | ||
79 | reply = edbus_message_method_return_new(message); | ||
80 | edbus_message_arguments_append(reply, "b", cache_desktop_exists()); | ||
81 | return reply; | ||
82 | } | ||
83 | |||
84 | static EDBus_Message * | ||
85 | add_desktop_dirs(const EDBus_Service_Interface *ifc EINA_UNUSED, const EDBus_Message *message) | ||
86 | { | ||
87 | EDBus_Message_Iter *array = NULL; | ||
88 | const char *dir; | ||
89 | |||
90 | if (!edbus_message_arguments_get(message, "as", &array)) | ||
91 | { | ||
92 | ERR("Error getting arguments."); | ||
93 | return NULL; | ||
94 | } | ||
95 | |||
96 | while (edbus_message_iter_get_and_next(array, 's', &dir)) | ||
97 | { | ||
98 | cache_desktop_dir_add(dir); | ||
99 | } | ||
100 | |||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | static EDBus_Message * | ||
105 | add_icon_dirs(const EDBus_Service_Interface *ifc EINA_UNUSED, const EDBus_Message *message) | ||
106 | { | ||
107 | EDBus_Message_Iter *array = NULL; | ||
108 | const char *dir; | ||
109 | |||
110 | if (!edbus_message_arguments_get(message, "as", &array)) | ||
111 | { | ||
112 | ERR("Error getting arguments."); | ||
113 | return NULL; | ||
114 | } | ||
115 | |||
116 | while (edbus_message_iter_get_and_next(array, 's', &dir)) | ||
117 | { | ||
118 | cache_icon_dir_add(dir); | ||
119 | } | ||
120 | |||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | static EDBus_Message * | ||
125 | build_desktop_cache(const EDBus_Service_Interface *ifc EINA_UNUSED, const EDBus_Message *message EINA_UNUSED) | ||
126 | { | ||
127 | const char *lang; | ||
128 | |||
129 | if (!edbus_message_arguments_get(message, "s", &lang)) | ||
130 | { | ||
131 | ERR("Error getting arguments."); | ||
132 | return NULL; | ||
133 | } | ||
134 | setenv("LANG", lang, 1); | ||
135 | |||
136 | cache_desktop_update(); | ||
137 | return NULL; | ||
138 | } | ||
139 | |||
140 | static EDBus_Message * | ||
141 | add_icon_exts(const EDBus_Service_Interface *ifc EINA_UNUSED, const EDBus_Message *message) | ||
142 | { | ||
143 | EDBus_Message_Iter *array = NULL; | ||
144 | const char *ext; | ||
145 | |||
146 | if (!edbus_message_arguments_get(message, "as", &array)) | ||
147 | { | ||
148 | ERR("Error getting arguments."); | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | while (edbus_message_iter_get_and_next(array, 's', &ext)) | ||
153 | { | ||
154 | cache_icon_ext_add(ext); | ||
155 | } | ||
156 | |||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | static const EDBus_Signal signals[] = { | ||
161 | [EFREET_SIGNAL_ICON_CACHE_UPDATE] = {"IconCacheUpdate", EDBUS_ARGS({ "b", "update" }), 0}, | ||
162 | [EFREET_SIGNAL_DESKTOP_CACHE_UPDATE] = {"DesktopCacheUpdate", EDBUS_ARGS({ "b", "update" }), 0}, | ||
163 | { NULL, NULL, 0 } | ||
164 | }; | ||
165 | |||
166 | static const EDBus_Method methods[] = { | ||
167 | { | ||
168 | "Register", EDBUS_ARGS({"s", "lang info"}), EDBUS_ARGS({"b", "cache exists"}), | ||
169 | do_register, 0 | ||
170 | }, | ||
171 | { | ||
172 | "AddDesktopDirs", EDBUS_ARGS({"as", "dirs"}), NULL, | ||
173 | add_desktop_dirs, EDBUS_METHOD_FLAG_NOREPLY | ||
174 | }, | ||
175 | { | ||
176 | "BuildDesktopCache", EDBUS_ARGS({"s", "lang info"}), NULL, | ||
177 | build_desktop_cache, EDBUS_METHOD_FLAG_NOREPLY | ||
178 | }, | ||
179 | { | ||
180 | "AddIconDirs", EDBUS_ARGS({"as", "dirs"}), NULL, | ||
181 | add_icon_dirs, EDBUS_METHOD_FLAG_NOREPLY | ||
182 | }, | ||
183 | { | ||
184 | "AddIconExts", EDBUS_ARGS({"as", "exts"}), NULL, | ||
185 | add_icon_exts, EDBUS_METHOD_FLAG_NOREPLY | ||
186 | }, | ||
187 | { NULL, NULL, NULL, NULL, 0 } | ||
188 | }; | ||
189 | |||
190 | static const EDBus_Service_Interface_Desc desc = { | ||
191 | INTERFACE, methods, signals, NULL, NULL, NULL | ||
192 | }; | ||
193 | |||
194 | static void | ||
195 | on_name_request(void *data EINA_UNUSED, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED) | ||
196 | { | ||
197 | unsigned int reply; | ||
198 | |||
199 | if (edbus_message_error_get(msg, NULL, NULL)) | ||
200 | { | ||
201 | ERR("error on on_name_request"); | ||
202 | quit(); | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | if (!edbus_message_arguments_get(msg, "u", &reply)) | ||
207 | { | ||
208 | ERR("error getting arguments on on_name_request"); | ||
209 | quit(); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | if (reply != EDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER) | ||
214 | { | ||
215 | ERR("error name already in use"); | ||
216 | quit(); | ||
217 | return; | ||
218 | } | ||
219 | INF("name requested"); | ||
220 | } | ||
221 | |||
222 | /* external */ | ||
223 | void | ||
224 | send_signal_icon_cache_update(Eina_Bool update) | ||
225 | { | ||
226 | edbus_service_signal_emit(iface, EFREET_SIGNAL_ICON_CACHE_UPDATE, update); | ||
227 | } | ||
228 | |||
229 | void | ||
230 | send_signal_desktop_cache_update(Eina_Bool update) | ||
231 | { | ||
232 | edbus_service_signal_emit(iface, EFREET_SIGNAL_DESKTOP_CACHE_UPDATE, update); | ||
233 | } | ||
234 | |||
235 | Eina_Bool | ||
236 | dbus_init(void) | ||
237 | { | ||
238 | if (!edbus_init()) return EINA_FALSE; | ||
239 | |||
240 | conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION); | ||
241 | if (!conn) goto conn_error; | ||
242 | |||
243 | edbus_connection_event_callback_add(conn, | ||
244 | EDBUS_CONNECTION_EVENT_DISCONNECTED, disconnected, NULL); | ||
245 | iface = edbus_service_interface_register(conn, PATH, &desc); | ||
246 | edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, | ||
247 | on_name_request, NULL); | ||
248 | |||
249 | return EINA_TRUE; | ||
250 | conn_error: | ||
251 | edbus_shutdown(); | ||
252 | return EINA_FALSE; | ||
253 | } | ||
254 | |||
255 | Eina_Bool | ||
256 | dbus_shutdown(void) | ||
257 | { | ||
258 | edbus_connection_unref(conn); | ||
259 | edbus_shutdown(); | ||
260 | return EINA_TRUE; | ||
261 | |||
262 | } | ||
diff --git a/src/bin/efreet/efreetd_dbus.h b/src/bin/efreet/efreetd_dbus.h new file mode 100644 index 0000000000..9e9fd70700 --- /dev/null +++ b/src/bin/efreet/efreetd_dbus.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __EFREETD_DBUS_H | ||
2 | #define __EFREETD_DBUS_H | ||
3 | |||
4 | void send_signal_icon_cache_update(Eina_Bool update); | ||
5 | void send_signal_desktop_cache_update(Eina_Bool update); | ||
6 | |||
7 | Eina_Bool dbus_init(void); | ||
8 | Eina_Bool dbus_shutdown(void); | ||
9 | |||
10 | #endif | ||