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