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