summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile_Ecore_X.am2
-rw-r--r--src/Makefile_Efreet.am222
-rw-r--r--src/bin/efreet/efreet_desktop_cache_create.c465
-rw-r--r--src/bin/efreet/efreet_icon_cache_create.c1070
-rw-r--r--src/bin/efreet/efreetd.c59
-rw-r--r--src/bin/efreet/efreetd.h34
-rw-r--r--src/bin/efreet/efreetd_cache.c575
-rw-r--r--src/bin/efreet/efreetd_cache.h13
-rw-r--r--src/bin/efreet/efreetd_dbus.c262
-rw-r--r--src/bin/efreet/efreetd_dbus.h10
-rw-r--r--src/lib/efreet/Efreet.h152
-rw-r--r--src/lib/efreet/Efreet_Mime.h129
-rw-r--r--src/lib/efreet/Efreet_Trash.h104
-rw-r--r--src/lib/efreet/efreet.c368
-rw-r--r--src/lib/efreet/efreet_alloca.h30
-rw-r--r--src/lib/efreet/efreet_base.c539
-rw-r--r--src/lib/efreet/efreet_base.h281
-rw-r--r--src/lib/efreet/efreet_cache.c1181
-rw-r--r--src/lib/efreet/efreet_cache_private.h60
-rw-r--r--src/lib/efreet/efreet_copy.h10
-rw-r--r--src/lib/efreet/efreet_desktop.c967
-rw-r--r--src/lib/efreet/efreet_desktop.h371
-rw-r--r--src/lib/efreet/efreet_desktop_command.c903
-rw-r--r--src/lib/efreet/efreet_icon.c796
-rw-r--r--src/lib/efreet/efreet_icon.h250
-rw-r--r--src/lib/efreet/efreet_ini.c578
-rw-r--r--src/lib/efreet/efreet_ini.h182
-rw-r--r--src/lib/efreet/efreet_menu.c3829
-rw-r--r--src/lib/efreet/efreet_menu.h139
-rw-r--r--src/lib/efreet/efreet_mime.c1612
-rw-r--r--src/lib/efreet/efreet_private.h231
-rw-r--r--src/lib/efreet/efreet_trash.c288
-rw-r--r--src/lib/efreet/efreet_uri.c119
-rw-r--r--src/lib/efreet/efreet_uri.h63
-rw-r--r--src/lib/efreet/efreet_utils.c474
-rw-r--r--src/lib/efreet/efreet_utils.h158
-rw-r--r--src/lib/efreet/efreet_xml.c609
-rw-r--r--src/lib/efreet/efreet_xml.h64
-rw-r--r--src/tests/efreet/compare/comp.h527
-rw-r--r--src/tests/efreet/compare/efreet_alloc.c30
-rw-r--r--src/tests/efreet/compare/efreet_menu_alloc.c23
-rw-r--r--src/tests/efreet/data/entrybin0 -> 647 bytes
-rw-r--r--src/tests/efreet/data/entry.pngbin0 -> 648 bytes
-rw-r--r--src/tests/efreet/data/long.ini3
-rw-r--r--src/tests/efreet/data/preferences.menu41
-rw-r--r--src/tests/efreet/data/sub/Makefile.am8
-rw-r--r--src/tests/efreet/data/sub/test.desktop5
-rw-r--r--src/tests/efreet/data/test.desktop10
-rw-r--r--src/tests/efreet/data/test.ini21
-rw-r--r--src/tests/efreet/data/test.menu52
-rw-r--r--src/tests/efreet/data/test_garbage2341
-rw-r--r--src/tests/efreet/data/test_menu_bad_comment.menu14
-rw-r--r--src/tests/efreet/data/test_menu_slash_bad.menu11
-rw-r--r--src/tests/efreet/data/test_type.desktop10
-rw-r--r--src/tests/efreet/ef_cache.c199
-rw-r--r--src/tests/efreet/ef_data_dirs.c330
-rw-r--r--src/tests/efreet/ef_desktop.c401
-rw-r--r--src/tests/efreet/ef_icon_theme.c605
-rw-r--r--src/tests/efreet/ef_ini.c174
-rw-r--r--src/tests/efreet/ef_locale.c85
-rw-r--r--src/tests/efreet/ef_menu.c150
-rw-r--r--src/tests/efreet/ef_mime.c57
-rw-r--r--src/tests/efreet/ef_test.h11
-rw-r--r--src/tests/efreet/ef_utils.c28
-rw-r--r--src/tests/efreet/efreet_icon_cache_dump.c120
-rw-r--r--src/tests/efreet/efreet_spec_test.c57
-rw-r--r--src/tests/efreet/efreet_suite.c103
-rw-r--r--src/tests/efreet/efreet_suite.h10
-rw-r--r--src/tests/efreet/efreet_test_efreet.c25
-rw-r--r--src/tests/efreet/efreet_test_efreet_cache.c25
-rw-r--r--src/tests/efreet/efreet_user_dir.c276
-rw-r--r--src/tests/efreet/main.c188
73 files changed, 23142 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index b109c65..8a90462 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,6 +7,7 @@ SUBDIRS = . benchmarks examples
7 7
8lib_LTLIBRARIES = 8lib_LTLIBRARIES =
9bin_PROGRAMS = 9bin_PROGRAMS =
10noinst_PROGRAMS =
10check_PROGRAMS = 11check_PROGRAMS =
11EXTRA_DIST = 12EXTRA_DIST =
12 13
@@ -59,6 +60,7 @@ endif
59include Makefile_Embryo.am 60include Makefile_Embryo.am
60include Makefile_Eio.am 61include Makefile_Eio.am
61include Makefile_EDBus.am 62include Makefile_EDBus.am
63include Makefile_Efreet.am
62 64
63.PHONY: benchmark examples 65.PHONY: benchmark examples
64 66
@@ -75,6 +77,7 @@ install-examples:
75 77
76clean-local: 78clean-local:
77 rm -rf bin/eet/*.gcno 79 rm -rf bin/eet/*.gcno
80 rm -rf bin/efreet/*.gcno
78 rm -rf lib/evil/*.gcno 81 rm -rf lib/evil/*.gcno
79 rm -rf lib/eina/*.gcno 82 rm -rf lib/eina/*.gcno
80 rm -rf lib/eo/*.gcno 83 rm -rf lib/eo/*.gcno
@@ -90,6 +93,7 @@ clean-local:
90 rm -rf lib/evas/file/*.gcno 93 rm -rf lib/evas/file/*.gcno
91 rm -rf lib/embryo/*.gcno 94 rm -rf lib/embryo/*.gcno
92 rm -rf lib/edbus/*.gcno 95 rm -rf lib/edbus/*.gcno
96 rm -rf lib/efreet/*.gcno
93 rm -rf modules/eina/mp/pass_through/*.gcno 97 rm -rf modules/eina/mp/pass_through/*.gcno
94 rm -rf modules/eina/mp/one_big/*.gcno 98 rm -rf modules/eina/mp/one_big/*.gcno
95 rm -rf modules/eina/mp/chained_pool/*.gcno 99 rm -rf modules/eina/mp/chained_pool/*.gcno
diff --git a/src/Makefile_Ecore_X.am b/src/Makefile_Ecore_X.am
index c1c81e8..36248fb 100644
--- a/src/Makefile_Ecore_X.am
+++ b/src/Makefile_Ecore_X.am
@@ -138,7 +138,7 @@ endif
138 138
139### Utils 139### Utils
140 140
141noinst_PROGRAMS = utils/ecore/makekeys 141noinst_PROGRAMS += utils/ecore/makekeys
142 142
143utils_ecore_makekeys_SOURCES = utils/ecore/makekeys.c 143utils_ecore_makekeys_SOURCES = utils/ecore/makekeys.c
144 144
diff --git a/src/Makefile_Efreet.am b/src/Makefile_Efreet.am
new file mode 100644
index 0000000..dd7bca9
--- /dev/null
+++ b/src/Makefile_Efreet.am
@@ -0,0 +1,222 @@
1
2### Library
3
4lib_LTLIBRARIES += \
5lib/efreet/libefreet.la \
6lib/efreet/libefreet_mime.la \
7lib/efreet/libefreet_trash.la
8
9EFREET_COMMON_CPPFLAGS = \
10-I$(top_srcdir)/src/lib/eina \
11-I$(top_builddir)/src/lib/eina \
12-I$(top_srcdir)/src/lib/eo \
13-I$(top_builddir)/src/lib/eo \
14-I$(top_srcdir)/src/lib/ecore \
15-I$(top_builddir)/src/lib/ecore \
16-I$(top_srcdir)/src/lib/ecore_file \
17-I$(top_builddir)/src/lib/ecore_file \
18-I$(top_srcdir)/src/lib/eet \
19-I$(top_builddir)/src/lib/eet \
20-I$(top_srcdir)/src/lib/edbus \
21-I$(top_builddir)/src/lib/edbus \
22-I$(top_srcdir)/src/lib/efreet \
23-I$(top_builddir)/src/lib/efreet \
24-DPACKAGE_LIB_DIR=\"$(libdir)\" \
25-DPACKAGE_DATA_DIR=\"$(datadir)\" \
26-DLOCALE_DIR=\"@LOCALE_DIR@\" \
27-DEFL_EFREET_BUILD \
28@EFL_CFLAGS@ \
29@EFL_COV_CFLAGS@ \
30@EFREET_CFLAGS@ \
31@USE_EVIL_CFLAGS@
32
33EFREET_COMMON_LIBADD = \
34lib/eina/libeina.la \
35lib/eo/libeo.la \
36lib/ecore/libecore.la \
37lib/ecore_file/libecore_file.la \
38lib/eet/libeet.la \
39lib/edbus/libedbus2.la \
40@USE_EVIL_LIBS@ \
41@EFREET_LIBS@ \
42@EFL_COV_LIBS@
43
44EFREET_COMMON_USER_LIBADD = $(EFREET_COMMON_LIBADD) lib/efreet/libefreet.la
45
46EFREET_COMMON_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
47
48installed_efreetmainheadersdir = $(includedir)/efreet-@VMAJ@
49dist_installed_efreetmainheaders_DATA = \
50lib/efreet/Efreet.h \
51lib/efreet/efreet_base.h \
52lib/efreet/efreet_desktop.h \
53lib/efreet/efreet_icon.h \
54lib/efreet/efreet_ini.h \
55lib/efreet/efreet_menu.h \
56lib/efreet/efreet_utils.h \
57lib/efreet/efreet_uri.h \
58lib/efreet/Efreet_Mime.h \
59lib/efreet/Efreet_Trash.h
60
61# libefreet.la
62lib_efreet_libefreet_la_SOURCES = \
63lib/efreet/efreet.c \
64lib/efreet/efreet_base.c \
65lib/efreet/efreet_icon.c \
66lib/efreet/efreet_xml.c \
67lib/efreet/efreet_ini.c \
68lib/efreet/efreet_desktop.c \
69lib/efreet/efreet_desktop_command.c \
70lib/efreet/efreet_menu.c \
71lib/efreet/efreet_utils.c \
72lib/efreet/efreet_uri.c \
73lib/efreet/efreet_cache.c \
74lib/efreet/efreet_private.h \
75lib/efreet/efreet_xml.h \
76lib/efreet/efreet_cache_private.h \
77lib/efreet/efreet_alloca.h
78
79lib_efreet_libefreet_la_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
80lib_efreet_libefreet_la_LIBADD = $(EFREET_COMMON_LIBADD)
81lib_efreet_libefreet_la_LDFLAGS = $(EFREET_COMMON_LDFLAGS)
82
83# libefreet_mime.la
84lib_efreet_libefreet_mime_la_SOURCES = lib/efreet/efreet_mime.c
85lib_efreet_libefreet_mime_la_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
86lib_efreet_libefreet_mime_la_LIBADD = $(EFREET_COMMON_USER_LIBADD)
87lib_efreet_libefreet_mime_la_LDFLAGS = $(EFREET_COMMON_LDFLAGS)
88
89# libefreet_trash.la
90lib_efreet_libefreet_trash_la_SOURCES = lib/efreet/efreet_trash.c
91lib_efreet_libefreet_trash_la_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
92lib_efreet_libefreet_trash_la_LIBADD = $(EFREET_COMMON_USER_LIBADD)
93lib_efreet_libefreet_trash_la_LDFLAGS = $(EFREET_COMMON_LDFLAGS)
94
95
96### Binary
97
98bin_PROGRAMS += bin/efreet/efreetd
99
100bin_efreet_efreetd_SOURCES = \
101bin/efreet/efreetd.c \
102bin/efreet/efreetd.h \
103bin/efreet/efreetd_dbus.h \
104bin/efreet/efreetd_dbus.c \
105bin/efreet/efreetd_cache.h \
106bin/efreet/efreetd_cache.c
107
108bin_efreet_efreetd_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
109bin_efreet_efreetd_LDADD = $(EFREET_COMMON_USER_LIBADD)
110
111efreetinternal_bindir=$(libdir)/efreet
112efreetinternal_bin_PROGRAMS = \
113bin/efreet/efreet_desktop_cache_create \
114bin/efreet/efreet_icon_cache_create
115
116bin_efreet_efreet_desktop_cache_create_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
117bin_efreet_efreet_desktop_cache_create_LDADD = $(EFREET_COMMON_USER_LIBADD)
118bin_efreet_efreet_desktop_cache_create_SOURCES = \
119bin/efreet/efreet_desktop_cache_create.c
120
121bin_efreet_efreet_icon_cache_create_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
122bin_efreet_efreet_icon_cache_create_LDADD = $(EFREET_COMMON_USER_LIBADD)
123bin_efreet_efreet_icon_cache_create_SOURCES = \
124bin/efreet/efreet_icon_cache_create.c
125
126### Unit tests
127
128if EFL_ENABLE_TESTS
129
130noinst_PROGRAMS += \
131tests/efreet/efreet_test \
132tests/efreet/efreet_spec_test \
133tests/efreet/efreet_cache_test \
134tests/efreet/efreet_icon_cache_dump \
135tests/efreet/efreet_user_dir \
136tests/efreet/compare/efreet_alloc \
137tests/efreet/compare/efreet_menu_alloc
138
139
140# efreet_test
141tests_efreet_efreet_test_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
142tests_efreet_efreet_test_LDADD = \
143$(EFREET_COMMON_USER_LIBADD) \
144lib/efreet/libefreet_mime.la
145
146tests_efreet_efreet_test_SOURCES = \
147tests/efreet/ef_test.h \
148tests/efreet/ef_data_dirs.c \
149tests/efreet/ef_icon_theme.c \
150tests/efreet/ef_ini.c \
151tests/efreet/ef_utils.c \
152tests/efreet/ef_desktop.c \
153tests/efreet/ef_menu.c \
154tests/efreet/ef_mime.c \
155tests/efreet/main.c
156
157# efreet_spec_test
158tests_efreet_efreet_spec_test_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
159tests_efreet_efreet_spec_test_LDADD = $(EFREET_COMMON_USER_LIBADD)
160tests_efreet_efreet_spec_test_SOURCES = \
161tests/efreet/efreet_spec_test.c
162
163# efreet_cache_test
164tests_efreet_efreet_cache_test_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
165tests_efreet_efreet_cache_test_LDADD = $(EFREET_COMMON_USER_LIBADD)
166tests_efreet_efreet_cache_test_SOURCES = \
167tests/efreet/ef_cache.c
168
169# efreet_icon_cache_dump
170tests_efreet_efreet_icon_cache_dump_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
171tests_efreet_efreet_icon_cache_dump_LDADD = $(EFREET_COMMON_USER_LIBADD)
172tests_efreet_efreet_icon_cache_dump_SOURCES = \
173tests/efreet/efreet_icon_cache_dump.c
174
175# efreet_user_dir
176tests_efreet_efreet_user_dir_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
177tests_efreet_efreet_user_dir_LDADD = $(EFREET_COMMON_USER_LIBADD)
178tests_efreet_efreet_user_dir_SOURCES = \
179tests/efreet/efreet_user_dir.c
180
181# efreet_alloc
182tests_efreet_compare_efreet_alloc_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
183tests_efreet_compare_efreet_alloc_LDADD = $(EFREET_COMMON_USER_LIBADD)
184tests_efreet_compare_efreet_alloc_SOURCES = \
185tests/efreet/compare/efreet_alloc.c \
186tests/efreet/compare/comp.h
187
188# efreet_menu_alloc
189tests_efreet_compare_efreet_menu_alloc_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS)
190tests_efreet_compare_efreet_menu_alloc_LDADD = $(EFREET_COMMON_USER_LIBADD)
191tests_efreet_compare_efreet_menu_alloc_SOURCES = \
192tests/efreet/compare/efreet_menu_alloc.c \
193tests/efreet/compare/comp.h
194
195efreettestdir = $(datadir)/efreet/test
196efreettest_DATA = \
197tests/efreet/data/test.ini \
198tests/efreet/data/long.ini \
199tests/efreet/data/test.desktop \
200tests/efreet/data/test_type.desktop \
201tests/efreet/data/test.menu \
202tests/efreet/data/test_menu_slash_bad.menu \
203tests/efreet/data/entry.png \
204tests/efreet/data/entry \
205tests/efreet/data/preferences.menu \
206tests/efreet/data/test_garbage
207
208efreettestsubdir = $(datadir)/efreet/test/sub
209efreettestsub_DATA = \
210tests/efreet/data/sub/test.desktop
211
212check_PROGRAMS += tests/efreet/efreet_suite
213
214tests_efreet_efreet_suite_SOURCES = \
215tests/efreet/efreet_suite.c \
216tests/efreet/efreet_test_efreet.c \
217tests/efreet/efreet_test_efreet_cache.c
218
219tests_efreet_efreet_suite_CPPFLAGS = $(EFREET_COMMON_CPPFLAGS) @CHECK_CFLAGS@
220tests_efreet_efreet_suite_LDADD = $(EFREET_COMMON_USER_LIBADD) @CHECK_LIBS@
221
222endif
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 0000000..db3118c
--- /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
15static int _efreet_desktop_cache_log_dom = -1;
16
17#include "Efreet.h"
18#include "efreet_private.h"
19#include "efreet_cache_private.h"
20
21static Eet_Data_Descriptor *edd = NULL;
22static Eet_File *ef = NULL;
23static Eet_File *util_ef = NULL;
24
25static Eina_Hash *desktops = NULL;
26
27static Eina_Hash *file_ids = NULL;
28static Efreet_Cache_Hash *old_file_ids = NULL;
29static Eina_Hash *paths = NULL;
30
31static Eina_Hash *mime_types = NULL;
32static Eina_Hash *categories = NULL;
33static Eina_Hash *startup_wm_class = NULL;
34static Eina_Hash *name = NULL;
35static Eina_Hash *generic_name = NULL;
36static Eina_Hash *comment = NULL;
37static Eina_Hash *exec = NULL;
38
39static int
40cache_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
126static int
127cache_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
174static int
175cache_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
199int
200main(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;
443error:
444 IF_FREE(dir);
445edd_error:
446 if (old_file_ids)
447 {
448 eina_hash_free(old_file_ids->hash);
449 free(old_file_ids);
450 }
451 efreet_shutdown();
452efreet_error:
453 ecore_shutdown();
454ecore_error:
455 eet_shutdown();
456eet_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();
462eina_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 0000000..662dd09
--- /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
18static int _efreet_icon_cache_log_dom = -1;
19
20#include "Efreet.h"
21#include "efreet_private.h"
22#include "efreet_cache_private.h"
23
24static Eina_Array *exts = NULL;
25static Eina_Array *extra_dirs = NULL;
26static Eina_Array *strs = NULL;
27static Eina_Hash *icon_themes = NULL;
28
29static Eina_Bool
30cache_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
53static Eina_Bool
54cache_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
64static Eina_Bool
65cache_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
120static Eina_Bool
121cache_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
154static Eina_Bool
155check_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
206static Eina_Bool
207cache_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
325static Eina_Bool
326cache_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
337static Eina_Bool
338cache_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
375static Eina_Bool
376check_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
405static Efreet_Icon_Theme_Directory *
406icon_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
473static Eina_Bool
474icon_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
590error:
591 efreet_ini_free(ini);
592
593 return EINA_TRUE;
594}
595
596static Eina_Bool
597cache_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
662static int
663cache_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
687static void
688icon_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
700int
701main(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");
1051on_error_efreet:
1052 efreet_shutdown();
1053 if (theme_ef) eet_close(theme_ef);
1054
1055on_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 0000000..a4ae720
--- /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
12int efreetd_log_dom = -1;
13
14void
15quit(void)
16{
17 ecore_main_loop_quit();
18}
19
20int
21main(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
47cache_error:
48 dbus_shutdown();
49dbus_error:
50 ecore_file_shutdown();
51ecore_file_error:
52 ecore_shutdown();
53ecore_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 0000000..a6931e3
--- /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
9extern 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
32void 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 0000000..5af928b
--- /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}
diff --git a/src/bin/efreet/efreetd_cache.h b/src/bin/efreet/efreetd_cache.h
new file mode 100644
index 0000000..2fb520e
--- /dev/null
+++ b/src/bin/efreet/efreetd_cache.h
@@ -0,0 +1,13 @@
1#ifndef __EFREETD_CACHE_H
2#define __EFREETD_CACHE_H
3
4void cache_desktop_dir_add(const char *dir);
5void cache_icon_dir_add(const char *dir);
6void cache_icon_ext_add(const char *ext);
7void cache_desktop_update(void);
8Eina_Bool cache_desktop_exists(void);
9
10Eina_Bool cache_init(void);
11Eina_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 0000000..b5e98ad
--- /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 */
16enum
17{
18 EFREET_SIGNAL_ICON_CACHE_UPDATE = 0,
19 EFREET_SIGNAL_DESKTOP_CACHE_UPDATE
20};
21
22static EDBus_Connection *conn;
23static EDBus_Service_Interface *iface;
24
25static Ecore_Timer *shutdown = NULL;
26static int clients = 0;
27
28static Eina_Bool
29do_shutdown(void *data EINA_UNUSED)
30{
31 quit();
32 return ECORE_CALLBACK_CANCEL;
33}
34
35static void
36disconnected(void *context EINA_UNUSED, EDBus_Connection *connection EINA_UNUSED, void *event_info EINA_UNUSED)
37{
38 INF("disconnected");
39 quit();
40}
41
42static void
43client_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
58static EDBus_Message *
59do_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
84static EDBus_Message *
85add_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
104static EDBus_Message *
105add_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
124static EDBus_Message *
125build_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
140static EDBus_Message *
141add_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
160static 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
166static 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
190static const EDBus_Service_Interface_Desc desc = {
191 INTERFACE, methods, signals, NULL, NULL, NULL
192};
193
194static void
195on_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 */
223void
224send_signal_icon_cache_update(Eina_Bool update)
225{
226 edbus_service_signal_emit(iface, EFREET_SIGNAL_ICON_CACHE_UPDATE, update);
227}
228
229void
230send_signal_desktop_cache_update(Eina_Bool update)
231{
232 edbus_service_signal_emit(iface, EFREET_SIGNAL_DESKTOP_CACHE_UPDATE, update);
233}
234
235Eina_Bool
236dbus_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;
250conn_error:
251 edbus_shutdown();
252 return EINA_FALSE;
253}
254
255Eina_Bool
256dbus_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 0000000..9e9fd70
--- /dev/null
+++ b/src/bin/efreet/efreetd_dbus.h
@@ -0,0 +1,10 @@
1#ifndef __EFREETD_DBUS_H
2#define __EFREETD_DBUS_H
3
4void send_signal_icon_cache_update(Eina_Bool update);
5void send_signal_desktop_cache_update(Eina_Bool update);
6
7Eina_Bool dbus_init(void);
8Eina_Bool dbus_shutdown(void);
9
10#endif
diff --git a/src/lib/efreet/Efreet.h b/src/lib/efreet/Efreet.h
new file mode 100644
index 0000000..ae1ec18
--- /dev/null
+++ b/src/lib/efreet/Efreet.h
@@ -0,0 +1,152 @@
1#ifndef EFREET_H
2#define EFREET_H
3
4/**
5 * @file Efreet.h
6 * @brief The file that must be included by any project wishing to use
7 * Efreet. Efreet.h provides all of the necessary headers and includes to
8 * work with Efreet.
9 */
10
11/**
12 * @page efreet_main Efreet
13 *
14 * @section toc Table of Contents
15 *
16 * @li @ref efreet_main_intro
17 * @li @ref efreet_main_compiling
18 * @li @ref efreet_main_next_steps
19 *
20 * @section efreet_main_intro Introduction
21 *
22 * Efreet is a library designed to help apps work several of the
23 * Freedesktop.org standards regarding Icons, Desktop files and Menus. To
24 * that end it implements the following specifications:
25 *
26 * @li XDG Base Directory Specification
27 * @li Icon Theme Specification
28 * @li Desktop Entry Specification
29 * @li Desktop Menu Specification
30 * @li FDO URI Specification
31 * @li Shared Mime Info Specification
32 * @li Trash Specification
33 *
34 * @section efreet_main_compiling How to compile
35 *
36 * Efreet is a library your application links to. The procedure for
37 * this is very simple. You simply have to compile your application
38 * with the appropriate compiler flags that the @c pkg-config script
39 * outputs. Mime and Thrash are separated modules. For example, to
40 * compile with mime support:
41 *
42 * Compiling C or C++ files into object files:
43 *
44 * @verbatim
45 gcc -c -o main.o main.c `pkg-config --cflags efreet efreet-mime`
46 @endverbatim
47 *
48 * Linking object files into a binary executable:
49 *
50 * @verbatim
51 gcc -o my_application main.o `pkg-config --libs efreet efreet-mime`
52 @endverbatim
53 *
54 * See @ref pkgconfig
55 *
56 * @section efreet_main_next_steps Next Steps
57 *
58 * After you understood what Efreet is and installed it in your system
59 * you should proceed understanding the programming interface.
60 *
61 * Recommended reading:
62 *
63 * @li @ref Efreet_Base for base directory specification (XDG variables).
64 * @li @ref Efreet_Desktop to access .desktop files
65 * @li @ref Efreet_Menu to access menus of .desktop files
66 * @li @ref Efreet_Mime to identify files based on extension or header.
67 * @li @ref Efreet_Trash to access file trash implementation.
68 * @li @ref Efreet_Ini for parsing INI-like key-value files.
69 * @li @ref Efreet_Uri for URI parsing and encoding.
70 * @li @ref Efreet_Utils general utilities.
71 *
72 */
73
74#include <Eina.h>
75
76#ifdef EAPI
77# undef EAPI
78#endif
79
80#ifdef _WIN32
81# ifdef EFL_EFREET_BUILD
82# ifdef DLL_EXPORT
83# define EAPI __declspec(dllexport)
84# else
85# define EAPI
86# endif /* ! DLL_EXPORT */
87# else
88# define EAPI __declspec(dllimport)
89# endif /* ! EFL_EFREET_BUILD */
90#else
91# ifdef __GNUC__
92# if __GNUC__ >= 4
93# define EAPI __attribute__ ((visibility("default")))
94# else
95# define EAPI
96# endif
97# else
98# define EAPI
99# endif
100#endif
101
102#ifdef __cplusplus
103extern "C" {
104#endif
105
106#define EFREET_VERSION_MAJOR 1
107#define EFREET_VERSION_MINOR 8
108
109 typedef struct _Efreet_Version
110 {
111 int major;
112 int minor;
113 int micro;
114 int revision;
115 } Efreet_Version;
116
117 EAPI extern Efreet_Version *efreet_version;
118
119#include "efreet_base.h"
120#include "efreet_ini.h"
121#include "efreet_icon.h"
122#include "efreet_desktop.h"
123#include "efreet_menu.h"
124#include "efreet_utils.h"
125#include "efreet_uri.h"
126
127/**
128 * @return Value > @c 0 if the initialization was successful, @c 0 otherwise.
129 * @brief Initializes the Efreet system
130 */
131EAPI int efreet_init(void);
132
133/**
134 * @return The number of times the init function has been called minus the
135 * corresponding init call.
136 * @brief Shuts down Efreet if a balanced number of init/shutdown calls have
137 * been made
138 */
139EAPI int efreet_shutdown(void);
140
141/**
142 * @brief Resets language dependent variables and resets language dependent
143 * caches This must be called whenever the locale is changed.
144 * @since 1.7
145 */
146EAPI void efreet_lang_reset(void);
147
148#ifdef __cplusplus
149}
150#endif
151
152#endif
diff --git a/src/lib/efreet/Efreet_Mime.h b/src/lib/efreet/Efreet_Mime.h
new file mode 100644
index 0000000..5bfd418
--- /dev/null
+++ b/src/lib/efreet/Efreet_Mime.h
@@ -0,0 +1,129 @@
1#ifndef EFREET_MIME_H
2#define EFREET_MIME_H
3
4/**
5 * @file Efreet_Mime.h
6 * @brief The file that must be included by any project wishing to use
7 * @addtogroup Efreet_Mime Efreet_Mime: The XDG Shared Mime Info standard
8 * Efreet Mime is a library designed to help apps work with the
9 * Freedesktop.org Shared Mime Info standard.
10 * Efreet_Mime.h provides all of the necessary headers and
11 * includes to work with Efreet_Mime.
12 *
13 * @ingroup Efreet
14 * @{
15 */
16
17#ifdef EAPI
18# undef EAPI
19#endif
20
21#ifdef _WIN32
22# ifdef EFL_EFREET_MIME_BUILD
23# ifdef DLL_EXPORT
24# define EAPI __declspec(dllexport)
25# else
26# define EAPI
27# endif /* ! DLL_EXPORT */
28# else
29# define EAPI __declspec(dllimport)
30# endif /* ! EFL_EFREET_MIME_BUILD */
31#else
32# ifdef __GNUC__
33# if __GNUC__ >= 4
34# define EAPI __attribute__ ((visibility("default")))
35# else
36# define EAPI
37# endif
38# else
39# define EAPI
40# endif
41#endif
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47
48/**
49 * @return @c 1 on success or @c 0 on failure.
50 * @brief Initializes the efreet mime settings
51 */
52EAPI int efreet_mime_init(void);
53
54/**
55 * @return The number of times the init function has been called minus the
56 * corresponding init call.
57 * @brief Shuts down Efreet mime settings system if a balanced number of
58 * init/shutdown calls have been made
59 */
60EAPI int efreet_mime_shutdown(void);
61
62/**
63 * @param file The file to find the mime type
64 * @return Mime type as a string.
65 * @brief Retrieve the mime type of a file
66 */
67EAPI const char *efreet_mime_type_get(const char *file);
68
69/**
70 * @param file The file to check the mime type
71 * @return Mime type as a string.
72 * @brief Retrieve the mime type of a file using magic
73 */
74EAPI const char *efreet_mime_magic_type_get(const char *file);
75
76/**
77 * @param file The file to check the mime type
78 * @return Mime type as a string.
79 * @brief Retrieve the mime type of a file using globs
80 */
81EAPI const char *efreet_mime_globs_type_get(const char *file);
82
83/**
84 * @param file The file to check the mime type
85 * @return Mime type as a string.
86 * @brief Retrieve the special mime type of a file
87 */
88EAPI const char *efreet_mime_special_type_get(const char *file);
89
90/**
91 * @param file The file to check the mime type
92 * @return Mime type as a string.
93 * @brief Retrieve the fallback mime type of a file.
94 */
95EAPI const char *efreet_mime_fallback_type_get(const char *file);
96
97
98/**
99 * @param mime The name of the mime type
100 * @param theme The name of the theme to search icons in
101 * @param size The wanted size of the icon
102 * @return Mime type icon path as a string.
103 * @brief Retrieve the mime type icon for a file.
104 */
105EAPI const char *efreet_mime_type_icon_get(const char *mime, const char *theme,
106 unsigned int size);
107
108/**
109 * @brief Clear mime icons mapping cache
110 */
111EAPI void efreet_mime_type_cache_clear(void);
112
113/**
114 * @brief Flush mime icons mapping cache
115 *
116 * Flush timeout is defined at compile time by
117 * EFREET_MIME_ICONS_FLUSH_TIMEOUT
118 */
119EAPI void efreet_mime_type_cache_flush(void);
120
121/**
122 * @}
123 */
124
125#ifdef __cplusplus
126}
127#endif
128
129#endif
diff --git a/src/lib/efreet/Efreet_Trash.h b/src/lib/efreet/Efreet_Trash.h
new file mode 100644
index 0000000..a32be65
--- /dev/null
+++ b/src/lib/efreet/Efreet_Trash.h
@@ -0,0 +1,104 @@
1#ifndef EFREET_TRASH_H
2#define EFREET_TRASH_H
3
4#ifdef EAPI
5# undef EAPI
6#endif
7
8#ifdef _WIN32
9# ifdef EFL_EFREET_TRASH_BUILD
10# ifdef DLL_EXPORT
11# define EAPI __declspec(dllexport)
12# else
13# define EAPI
14# endif /* ! DLL_EXPORT */
15# else
16# define EAPI __declspec(dllimport)
17# endif /* ! EFL_EFREET_TRASH_BUILD */
18#else
19# ifdef __GNUC__
20# if __GNUC__ >= 4
21# define EAPI __attribute__ ((visibility("default")))
22# else
23# define EAPI
24# endif
25# else
26# define EAPI
27# endif
28#endif
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34/**
35 * @file Efreet_Trash.h
36 * @brief Contains the methods used to support the FDO trash specification.
37 * @addtogroup Efreet_Trash Efreet_Trash: The XDG Trash Specification
38 * Efreet_Trash.h provides all of the necessary headers and includes to
39 * work with Efreet_Trash.
40 *
41 * @ingroup Efreet
42 * @{
43 */
44
45/**
46 * @return @c 1 on success or @c 0 on failure.
47 * @brief Initializes the efreet trash system
48 */
49EAPI int efreet_trash_init(void);
50
51/**
52 * @return No value.
53 * @brief Cleans up the efreet trash system
54 */
55EAPI int efreet_trash_shutdown(void);
56
57/**
58 * @return The XDG Trash local directory or @c NULL on errors.
59 * Return value must be freed with eina_stringshare_del.
60 * @brief Retrieves the XDG Trash local directory
61 */
62EAPI const char *efreet_trash_dir_get(const char *for_file);
63
64/**
65 * @param uri The local uri to move in the trash
66 * @param force_delete If you set this to @c 1 than files on different filesystems
67 * will be deleted permanently
68 * @return @c 1 on success, @c 0 on failure or @c -1 in case the uri is not on
69 * the same filesystem and force_delete is not set.
70 * @brief This function try to move the given uri to the trash. Files on
71 * different filesystem can't be moved to trash. If force_delete
72 * is @c 0 than non-local files will be ignored and @c -1 is returned, if you set
73 * force_delete to @c 1 non-local files will be deleted without asking.
74 */
75EAPI int efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete);
76
77/**
78 * @return A list of strings with filename (remember to free the list
79 * when you don't need anymore).
80 * @brief List all the files and directory currently inside the trash.
81 */
82EAPI Eina_List *efreet_trash_ls(void);
83
84/**
85 * @return @c 1 if the trash is empty or @c 0 if some file are in.
86 * @brief Check if the trash is currently empty
87 */
88EAPI int efreet_trash_is_empty(void);
89
90/**
91 * @return @c 1 on success or @c 0 on failure.
92 * @brief Delete all the files inside the trash.
93 */
94EAPI int efreet_trash_empty_trash(void);
95
96/**
97 * @}
98 */
99
100#ifdef __cplusplus
101}
102#endif
103
104#endif
diff --git a/src/lib/efreet/efreet.c b/src/lib/efreet/efreet.c
new file mode 100644
index 0000000..fcc0cfb
--- /dev/null
+++ b/src/lib/efreet/efreet.c
@@ -0,0 +1,368 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "efreet_alloca.h"
6
7#include <unistd.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10
11#include <Eet.h>
12#include <Ecore.h>
13#include <Ecore_File.h>
14
15/* define macros and variable for using the eina logging system */
16#define EFREET_MODULE_LOG_DOM /* no logging in this file */
17
18#include "Efreet.h"
19#include "efreet_private.h"
20#include "efreet_xml.h"
21
22/*
23 * Needs EAPI because of helper binaries
24 */
25EAPI int efreet_cache_update = 1;
26
27static int _efreet_init_count = 0;
28static int efreet_parsed_locale = 0;
29static const char *efreet_lang = NULL;
30static const char *efreet_lang_country = NULL;
31static const char *efreet_lang_modifier = NULL;
32static const char *efreet_language = NULL;
33static void efreet_parse_locale(void);
34static int efreet_parse_locale_setting(const char *env);
35
36#ifndef _WIN32
37static uid_t ruid;
38static uid_t rgid;
39#endif
40
41EAPI int
42efreet_init(void)
43{
44#ifndef _WIN32
45 char *tmp;
46#endif
47
48 if (++_efreet_init_count != 1)
49 return _efreet_init_count;
50
51#ifndef _WIN32
52 /* Find users real uid and gid */
53 tmp = getenv("SUDO_UID");
54 if (tmp)
55 ruid = strtoul(tmp, NULL, 10);
56 else
57 ruid = getuid();
58
59 tmp = getenv("SUDO_GID");
60 if (tmp)
61 rgid = strtoul(tmp, NULL, 10);
62 else
63 rgid = getgid();
64#endif
65
66 if (!eina_init())
67 return --_efreet_init_count;
68 if (!eet_init())
69 goto shutdown_eina;
70 if (!ecore_init())
71 goto shutdown_eet;
72 if (!ecore_file_init())
73 goto shutdown_ecore;
74
75 if (!efreet_base_init())
76 goto shutdown_ecore_file;
77
78 if (!efreet_cache_init())
79 goto shutdown_efreet_base;
80
81 if (!efreet_xml_init())
82 goto shutdown_efreet_cache;
83
84 if (!efreet_icon_init())
85 goto shutdown_efreet_xml;
86
87 if (!efreet_ini_init())
88 goto shutdown_efreet_icon;
89
90 if (!efreet_desktop_init())
91 goto shutdown_efreet_ini;
92
93 if (!efreet_menu_init())
94 goto shutdown_efreet_desktop;
95
96 if (!efreet_util_init())
97 goto shutdown_efreet_menu;
98
99#ifdef ENABLE_NLS
100 bindtextdomain(PACKAGE, LOCALE_DIR);
101 bind_textdomain_codeset(PACKAGE, "UTF-8");
102#endif
103
104 return _efreet_init_count;
105
106shutdown_efreet_menu:
107 efreet_menu_shutdown();
108shutdown_efreet_desktop:
109 efreet_desktop_shutdown();
110shutdown_efreet_ini:
111 efreet_ini_shutdown();
112shutdown_efreet_icon:
113 efreet_icon_shutdown();
114shutdown_efreet_xml:
115 efreet_xml_shutdown();
116shutdown_efreet_cache:
117 efreet_cache_shutdown();
118shutdown_efreet_base:
119 efreet_base_shutdown();
120shutdown_ecore_file:
121 ecore_file_shutdown();
122shutdown_ecore:
123 ecore_shutdown();
124shutdown_eet:
125 eet_shutdown();
126shutdown_eina:
127 eina_shutdown();
128
129 return --_efreet_init_count;
130}
131
132EAPI int
133efreet_shutdown(void)
134{
135 if (_efreet_init_count <= 0)
136 {
137 EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
138 return 0;
139 }
140 if (--_efreet_init_count != 0)
141 return _efreet_init_count;
142
143 efreet_util_shutdown();
144 efreet_menu_shutdown();
145 efreet_desktop_shutdown();
146 efreet_ini_shutdown();
147 efreet_icon_shutdown();
148 efreet_xml_shutdown();
149 efreet_cache_shutdown();
150 efreet_base_shutdown();
151
152 IF_RELEASE(efreet_lang);
153 IF_RELEASE(efreet_lang_country);
154 IF_RELEASE(efreet_lang_modifier);
155 IF_RELEASE(efreet_language);
156 efreet_parsed_locale = 0; /* reset this in case they init efreet again */
157
158 ecore_file_shutdown();
159 ecore_shutdown();
160 eet_shutdown();
161 eina_shutdown();
162
163 return _efreet_init_count;
164}
165
166EAPI void
167efreet_lang_reset(void)
168{
169 IF_RELEASE(efreet_lang);
170 IF_RELEASE(efreet_lang_country);
171 IF_RELEASE(efreet_lang_modifier);
172 IF_RELEASE(efreet_language);
173 efreet_parsed_locale = 0; /* reset this in case they init efreet again */
174
175 efreet_dirs_reset();
176 efreet_parse_locale();
177 efreet_cache_desktop_close();
178 efreet_cache_desktop_build();
179}
180
181/**
182 * @internal
183 * @return Returns the current users language setting or NULL if none set
184 * @brief Retrieves the current language setting
185 */
186const char *
187efreet_lang_get(void)
188{
189 if (efreet_parsed_locale) return efreet_lang;
190
191 efreet_parse_locale();
192 return efreet_lang;
193}
194
195/**
196 * @internal
197 * @return Returns the current language country setting or NULL if none set
198 * @brief Retrieves the current country setting for the current language or
199 */
200const char *
201efreet_lang_country_get(void)
202{
203 if (efreet_parsed_locale) return efreet_lang_country;
204
205 efreet_parse_locale();
206 return efreet_lang_country;
207}
208
209/**
210 * @internal
211 * @return Returns the current language modifier setting or NULL if none
212 * set.
213 * @brief Retrieves the modifier setting for the language.
214 */
215const char *
216efreet_lang_modifier_get(void)
217{
218 if (efreet_parsed_locale) return efreet_lang_modifier;
219
220 efreet_parse_locale();
221 return efreet_lang_modifier;
222}
223
224EAPI const char *
225efreet_language_get(void)
226{
227 if (efreet_parsed_locale) return efreet_language;
228
229 efreet_parse_locale();
230 return efreet_language;
231}
232
233/**
234 * @internal
235 * @return Returns no value
236 * @brief Parses out the language, country and modifer setting from the
237 * LC_MESSAGES environment variable
238 */
239static void
240efreet_parse_locale(void)
241{
242 efreet_parsed_locale = 1;
243
244 if (efreet_parse_locale_setting("LANG"))
245 return;
246
247 if (efreet_parse_locale_setting("LC_ALL"))
248 return;
249
250 if (efreet_parse_locale_setting("LC_MESSAGES"))
251 return;
252
253 efreet_language = eina_stringshare_add("C");
254}
255
256/**
257 * @internal
258 * @param env The environment variable to grab
259 * @return Returns 1 if we parsed something of @a env, 0 otherwise
260 * @brief Tries to parse the lang settings out of the given environment
261 * variable
262 */
263static int
264efreet_parse_locale_setting(const char *env)
265{
266 int found = 0;
267 char *setting;
268 char *p;
269 size_t len;
270
271 p = getenv(env);
272 if (!p) return 0;
273 len = strlen(p) + 1;
274 setting = alloca(len);
275 memcpy(setting, p, len);
276
277 /* pull the modifier off the end */
278 p = strrchr(setting, '@');
279 if (p)
280 {
281 *p = '\0';
282 efreet_lang_modifier = eina_stringshare_add(p + 1);
283 found = 1;
284 }
285
286 /* if there is an encoding we ignore it */
287 p = strrchr(setting, '.');
288 if (p) *p = '\0';
289
290 /* get the country if available */
291 p = strrchr(setting, '_');
292 if (p)
293 {
294 *p = '\0';
295 efreet_lang_country = eina_stringshare_add(p + 1);
296 found = 1;
297 }
298
299 if (*setting != '\0')
300 {
301 efreet_lang = eina_stringshare_add(setting);
302 found = 1;
303 }
304
305 if (found)
306 efreet_language = eina_stringshare_add(getenv(env));
307 return found;
308}
309
310/**
311 * @internal
312 * @param buffer The destination buffer
313 * @param size The destination buffer size
314 * @param strs The strings to concatenate together
315 * @return Returns the size of the string in @a buffer
316 * @brief Concatenates the strings in @a strs into the given @a buffer not
317 * exceeding the given @a size.
318 */
319size_t
320efreet_array_cat(char *buffer, size_t size, const char *strs[])
321{
322 int i;
323 size_t n;
324 for (i = 0, n = 0; n < size && strs[i]; i++)
325 {
326 n += eina_strlcpy(buffer + n, strs[i], size - n);
327 }
328 return n;
329}
330
331#ifndef _WIN32
332EAPI void
333efreet_fsetowner(int fd)
334{
335 struct stat st;
336
337 if (fd < 0) return;
338 if (fstat(fd, &st) < 0) return;
339 if (st.st_uid == ruid) return;
340
341 if (fchown(fd, ruid, rgid) != 0) return;
342}
343#else
344EAPI void
345efreet_fsetowner(int fd EINA_UNUSED)
346{
347}
348#endif
349
350#ifndef _WIN32
351EAPI void
352efreet_setowner(const char *path)
353{
354 EINA_SAFETY_ON_NULL_RETURN(path);
355
356 int fd;
357
358 fd = open(path, O_RDONLY);
359 if (fd < 0) return;
360 efreet_fsetowner(fd);
361 close(fd);
362}
363#else
364EAPI void
365efreet_setowner(const char *path EINA_UNUSED)
366{
367}
368#endif
diff --git a/src/lib/efreet/efreet_alloca.h b/src/lib/efreet/efreet_alloca.h
new file mode 100644
index 0000000..58a7398
--- /dev/null
+++ b/src/lib/efreet/efreet_alloca.h
@@ -0,0 +1,30 @@
1#ifndef EFREET_ALLOCA_H
2#define EFREET_ALLOCA_H
3
4#ifdef STDC_HEADERS
5# include <stdlib.h>
6# include <stddef.h>
7#else
8# ifdef HAVE_STDLIB_H
9# include <stdlib.h>
10# endif
11#endif
12#ifdef HAVE_ALLOCA_H
13# include <alloca.h>
14#elif !defined alloca
15# ifdef __GNUC__
16# define alloca __builtin_alloca
17# elif defined _AIX
18# define alloca __alloca
19# elif defined _MSC_VER
20# include <malloc.h>
21# define alloca _alloca
22# elif !defined HAVE_ALLOCA
23# ifdef __cplusplus
24extern "C"
25# endif
26void *alloca (size_t);
27# endif
28#endif
29
30#endif
diff --git a/src/lib/efreet/efreet_base.c b/src/lib/efreet/efreet_base.c
new file mode 100644
index 0000000..0c0b286
--- /dev/null
+++ b/src/lib/efreet/efreet_base.c
@@ -0,0 +1,539 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "efreet_alloca.h"
6
7#include <unistd.h>
8#include <ctype.h>
9
10#ifdef _WIN32
11# include <winsock2.h>
12#endif
13
14/* define macros and variable for using the eina logging system */
15#define EFREET_MODULE_LOG_DOM _efreet_base_log_dom
16static int _efreet_base_log_dom = -1;
17
18#include "Efreet.h"
19#include "efreet_private.h"
20
21#include <Ecore_File.h>
22
23static Efreet_Version _version = { VMAJ, VMIN, VMIC, VREV };
24EAPI Efreet_Version *efreet_version = &_version;
25
26#ifdef _WIN32
27# define EFREET_PATH_SEP ';'
28#else
29# define EFREET_PATH_SEP ':'
30#endif
31
32static const char *efreet_home_dir = NULL;
33static const char *xdg_data_home = NULL;
34static const char *xdg_config_home = NULL;
35static const char *xdg_cache_home = NULL;
36static const char *xdg_runtime_dir = NULL;
37static Eina_List *xdg_data_dirs = NULL;
38static Eina_List *xdg_config_dirs = NULL;
39static const char *xdg_desktop_dir = NULL;
40static const char *xdg_download_dir = NULL;
41static const char *xdg_templates_dir = NULL;
42static const char *xdg_publicshare_dir = NULL;
43static const char *xdg_documents_dir = NULL;
44static const char *xdg_music_dir = NULL;
45static const char *xdg_pictures_dir = NULL;
46static const char *xdg_videos_dir = NULL;
47static const char *hostname = NULL;
48
49static const char *efreet_dir_get(const char *key, const char *fallback);
50static Eina_List *efreet_dirs_get(const char *key,
51 const char *fallback);
52static const char *efreet_user_dir_get(const char *key, const char *fallback);
53
54/**
55 * @internal
56 * @return Returns @c 1 on success or @c 0 on failure
57 * @brief Initializes the efreet base settings
58 */
59int
60efreet_base_init(void)
61{
62 _efreet_base_log_dom = eina_log_domain_register
63 ("efreet_base", EFREET_DEFAULT_LOG_COLOR);
64 if (_efreet_base_log_dom < 0)
65 {
66 EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_base.\n");
67 return 0;
68 }
69 return 1;
70}
71
72/**
73 * @internal
74 * @return Returns no value
75 * @brief Cleans up the efreet base settings system
76 */
77void
78efreet_base_shutdown(void)
79{
80 IF_RELEASE(efreet_home_dir);
81 IF_RELEASE(xdg_desktop_dir);
82 IF_RELEASE(xdg_download_dir);
83 IF_RELEASE(xdg_templates_dir);
84 IF_RELEASE(xdg_publicshare_dir);
85 IF_RELEASE(xdg_documents_dir);
86 IF_RELEASE(xdg_music_dir);
87 IF_RELEASE(xdg_pictures_dir);
88 IF_RELEASE(xdg_videos_dir);
89
90 IF_RELEASE(xdg_data_home);
91 IF_RELEASE(xdg_config_home);
92 IF_RELEASE(xdg_cache_home);
93 IF_RELEASE(xdg_runtime_dir);
94
95 IF_FREE_LIST(xdg_data_dirs, eina_stringshare_del);
96 IF_FREE_LIST(xdg_config_dirs, eina_stringshare_del);
97
98 IF_RELEASE(hostname);
99
100 eina_log_domain_unregister(_efreet_base_log_dom);
101 _efreet_base_log_dom = -1;
102}
103
104/**
105 * @internal
106 * @return Returns the users home directory
107 * @brief Gets the users home directory and returns it.
108 */
109const char *
110efreet_home_dir_get(void)
111{
112 if (efreet_home_dir) return efreet_home_dir;
113
114 efreet_home_dir = getenv("HOME");
115#ifdef _WIN32
116 if (!efreet_home_dir || efreet_home_dir[0] == '\0')
117 efreet_home_dir = getenv("USERPROFILE");
118#endif
119 if (!efreet_home_dir || efreet_home_dir[0] == '\0')
120 efreet_home_dir = "/tmp";
121
122 efreet_home_dir = eina_stringshare_add(efreet_home_dir);
123
124 return efreet_home_dir;
125}
126
127EAPI const char *
128efreet_desktop_dir_get(void)
129{
130 if (xdg_desktop_dir) return xdg_desktop_dir;
131 xdg_desktop_dir = efreet_user_dir_get("XDG_DESKTOP_DIR", _("Desktop"));
132 return xdg_desktop_dir;
133}
134
135EAPI const char *
136efreet_download_dir_get(void)
137{
138 if (xdg_download_dir) return xdg_download_dir;
139 xdg_download_dir = efreet_user_dir_get("XDG_DOWNLOAD_DIR", _("Downloads"));
140 return xdg_download_dir;
141}
142
143EAPI const char *
144efreet_templates_dir_get(void)
145{
146 if (xdg_templates_dir) return xdg_templates_dir;
147 xdg_templates_dir = efreet_user_dir_get("XDG_TEMPLATES_DIR",
148 _("Templates"));
149 return xdg_templates_dir;
150}
151
152EAPI const char *
153efreet_public_share_dir_get(void)
154{
155 if (xdg_publicshare_dir) return xdg_publicshare_dir;
156 xdg_publicshare_dir = efreet_user_dir_get("XDG_PUBLICSHARE_DIR",
157 _("Public"));
158 return xdg_publicshare_dir;
159}
160
161EAPI const char *
162efreet_documents_dir_get(void)
163{
164 if (xdg_documents_dir) return xdg_documents_dir;
165 xdg_documents_dir = efreet_user_dir_get("XDG_DOCUMENTS_DIR",
166 _("Documents"));
167 return xdg_documents_dir;
168}
169
170EAPI const char *
171efreet_music_dir_get(void)
172{
173 if (xdg_music_dir) return xdg_music_dir;
174 xdg_music_dir = efreet_user_dir_get("XDG_MUSIC_DIR", _("Music"));
175 return xdg_music_dir;
176}
177
178EAPI const char *
179efreet_pictures_dir_get(void)
180{
181 if (xdg_pictures_dir) return xdg_pictures_dir;
182 xdg_pictures_dir = efreet_user_dir_get("XDG_PICTURES_DIR", _("Pictures"));
183 return xdg_pictures_dir;
184}
185
186EAPI const char *
187efreet_videos_dir_get(void)
188{