summaryrefslogtreecommitdiff
path: root/src/bin/efreet/efreetd_cache.c
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/bin/efreet/efreetd_cache.c
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/bin/efreet/efreetd_cache.c')
-rw-r--r--src/bin/efreet/efreetd_cache.c575
1 files changed, 575 insertions, 0 deletions
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
17static Eina_Hash *change_monitors = NULL;
18
19static Ecore_Event_Handler *cache_exe_del_handler = NULL;
20static Ecore_Event_Handler *cache_exe_data_handler = NULL;
21static Ecore_Exe *icon_cache_exe = NULL;
22static Ecore_Exe *desktop_cache_exe = NULL;
23static Ecore_Timer *icon_cache_timer = NULL;
24static Ecore_Timer *desktop_cache_timer = NULL;
25
26static Eina_Bool desktop_exists = EINA_FALSE;
27
28static Eina_List *desktop_system_dirs = NULL;
29static Eina_List *desktop_extra_dirs = NULL;
30static Eina_List *icon_extra_dirs = NULL;
31static Eina_List *icon_exts = NULL;
32static Eina_Bool icon_flush = EINA_FALSE;
33
34static Eina_Bool desktop_queue = EINA_FALSE;
35static Eina_Bool icon_queue = EINA_FALSE;
36
37static void desktop_changes_monitor_add(const char *path);
38
39/* internal */
40static Eina_Bool
41icon_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
95static void
96cache_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
105static Eina_Bool
106desktop_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
143static Eina_Bool
144cache_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
171static Eina_Bool
172cache_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
190static void
191icon_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
217static void
218icon_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
231static void
232icon_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
259static void
260icon_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
292static void
293desktop_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
330static void
331desktop_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
344static void
345desktop_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
363static void
364desktop_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
376static void
377fill_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);
396error:
397 eina_file_close(f);
398}
399
400static void
401read_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
408static void
409save_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
424static int
425strcmplen(const void *data1, const void *data2)
426{
427 return strncmp(data1, data2, eina_stringshare_strlen(data1));
428}
429
430/* external */
431void
432cache_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
456void
457cache_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
472void
473cache_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
483void
484cache_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
491Eina_Bool
492cache_desktop_exists(void)
493{
494 return desktop_exists;
495}
496
497Eina_Bool
498cache_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;
543error:
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
551Eina_Bool
552cache_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}