1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #include <Elementary.h>
6 #include "../../static_libs/buildsystem/buildsystem.h"
7 #include "elm_priv.h"
8
9 /* what are moodules in elementary for? for modularising behavior and features
10 * so they can be plugged in and out where you dont want the core source to
11 * always behave like that or do it that way. plug it at runtime!
12 *
13 * they have module names (in config) and "slots" to plug that module into
14 * to server a purpose. eg you plug plugin "xx" into the "entry-copy-paste"
15 * slot so it would provide replacement copy & paste ui functionality and
16 * specific symbols
17 *
18 * config is something like:
19 *
20 * export ELM_MODULES="xx>slot1:yy>slot2"
21 *
22 * where a module named xx is plugged into slot1 & yy is plugged into slot2
23 *
24 * real examples:
25 *
26 * export ELM_MODULES="my_module>entry/api"
27 *
28 * this loads the module called "my_module" into the slot "entry/api" which
29 * is an api slot for entry modules to modify behavior and hook to
30 * creation/deletion of the entry as well as replace the longpress behavior.
31 */
32 static Eina_Hash *modules = NULL;
33 static Eina_Hash *modules_as = NULL;
34
35 void
_elm_module_init(void)36 _elm_module_init(void)
37 {
38 modules = eina_hash_string_small_new(NULL);
39 modules_as = eina_hash_string_small_new(NULL);
40 }
41
42 void
_elm_module_shutdown(void)43 _elm_module_shutdown(void)
44 {
45 Eina_Iterator *it;
46 Elm_Module *m;
47
48 if (modules)
49 {
50 Eina_List *tl = NULL;
51
52 it = eina_hash_iterator_data_new(modules);
53
54 EINA_ITERATOR_FOREACH(it, m) tl = eina_list_append(tl, m);
55 eina_iterator_free(it);
56
57 EINA_LIST_FREE(tl, m) _elm_module_del(m);
58
59 ELM_SAFE_FREE(modules, eina_hash_free);
60 }
61
62 ELM_SAFE_FREE(modules_as, eina_hash_free);
63 }
64
65 void
_elm_module_parse(const char * s)66 _elm_module_parse(const char *s)
67 {
68 const char *p, *pe;
69
70 p = s;
71 pe = p;
72 for (;;)
73 {
74 if ((*pe == ':') || (!*pe))
75 { // p -> pe == 'name:'
76 if (pe > p)
77 {
78 char *n = malloc(pe - p + 1);
79 if (n)
80 {
81 char *nn;
82
83 strncpy(n, p, pe - p);
84 n[pe - p] = 0;
85 nn = strchr(n, '>');
86 if (nn)
87 {
88 *nn = 0;
89 nn++;
90 _elm_module_add(n, nn);
91 }
92 free(n);
93 }
94 }
95 if (!*pe) break;
96 p = pe + 1;
97 pe = p;
98 }
99 else
100 pe++;
101 }
102 }
103
104 Elm_Module *
_elm_module_find_as(const char * as)105 _elm_module_find_as(const char *as)
106 {
107 Elm_Module *m;
108
109 m = eina_hash_find(modules_as, as);
110 if (!m) return NULL;
111
112 if (!_elm_module_load(m))
113 {
114 ERR("Failed to load elementary module: '%s': %m", m->as);
115 _elm_module_del(m);
116 return NULL;
117 }
118 return m;
119 }
120
121 #if defined(_WIN32) || defined(__CYGWIN__)
122 # define EFL_SHARED_EXTENSION ".dll"
123 #else
124 # define EFL_SHARED_EXTENSION ".so"
125 #endif
126
127 Eina_Bool
_elm_module_load(Elm_Module * m)128 _elm_module_load(Elm_Module *m)
129 {
130 char buf[PATH_MAX];
131
132 if (m->module) return EINA_TRUE;
133 if (strchr(m->name, '/')) return EINA_FALSE;
134
135 #ifdef NEED_RUN_IN_TREE
136 if (getenv("EFL_RUN_IN_TREE"))
137 {
138 bs_mod_get(buf, sizeof(buf), "elementary", m->name);
139 }
140 else
141 #endif
142 {
143 snprintf(buf, sizeof(buf), "%s/elementary/modules/%s/%s/module"EFL_SHARED_EXTENSION,
144 _elm_lib_dir, m->name, MODULE_ARCH);
145 }
146 m->module = eina_module_new(buf);
147 if ((m->module) && (eina_module_load(m->module) == EINA_TRUE))
148 {
149 m->init_func = eina_module_symbol_get(m->module, "elm_modapi_init");
150 if (m->init_func)
151 {
152 m->shutdown_func =
153 eina_module_symbol_get(m->module, "elm_modapi_shutdown");
154 m->so_path = eina_stringshare_add(buf);
155 snprintf(buf, sizeof(buf), "%s/elementary/modules/%s/%s",
156 _elm_lib_dir, m->name, MODULE_ARCH);
157 m->bin_dir = eina_stringshare_add(buf);
158 snprintf(buf, sizeof(buf), "%s/elementary/modules/%s",
159 _elm_lib_dir, m->name);
160 m->data_dir = eina_stringshare_add(buf);
161 }
162 else
163 {
164 if (m->module)
165 {
166 eina_module_unload(m->module);
167 eina_module_free(m->module);
168 m->module = NULL;
169 }
170 return EINA_FALSE;
171 }
172 }
173 else if (m->module)
174 {
175 eina_module_free(m->module);
176 m->module = NULL;
177 }
178
179 if (!m->module) return EINA_FALSE;
180 return EINA_TRUE;
181 }
182
183 void
_elm_module_unload(Elm_Module * m)184 _elm_module_unload(Elm_Module *m)
185 {
186 eina_stringshare_del(m->so_path);
187 eina_stringshare_del(m->data_dir);
188 eina_stringshare_del(m->bin_dir);
189 ELM_SAFE_FREE(m->api, free);
190 if (m->module)
191 {
192 if (m->shutdown_func) m->shutdown_func(m);
193 eina_module_unload(m->module);
194 eina_module_free(m->module);
195 m->module = NULL;
196 }
197 m->shutdown_func = NULL;
198 m->init_func = NULL;
199 }
200
201 Elm_Module *
_elm_module_add(const char * name,const char * as)202 _elm_module_add(const char *name, const char *as)
203 {
204 Elm_Module *m;
205
206 if (name[0] == '/') return NULL;
207
208 m = eina_hash_find(modules, name);
209 if (m)
210 {
211 m->references++;
212 return m;
213 }
214 m = calloc(1, sizeof(Elm_Module));
215 if (!m) return NULL;
216 m->version = 1;
217 m->name = eina_stringshare_add(name);
218 m->references = 1;
219 eina_hash_direct_add(modules, m->name, m);
220 m->as = eina_stringshare_add(as);
221 eina_hash_direct_add(modules_as, m->as, m);
222 return m;
223 }
224
225 void
_elm_module_del(Elm_Module * m)226 _elm_module_del(Elm_Module *m)
227 {
228 m->references--;
229 if (m->references > 0) return;
230 _elm_module_unload(m);
231 eina_hash_del(modules, m->name, m);
232 eina_hash_del(modules_as, m->as, m);
233 eina_stringshare_del(m->name);
234 eina_stringshare_del(m->as);
235 free(m);
236 }
237
238 const void *
_elm_module_symbol_get(Elm_Module * m,const char * name)239 _elm_module_symbol_get(Elm_Module *m, const char *name)
240 {
241 return eina_module_symbol_get(m->module, name);
242 }
243